Gain/Balance/Mix/Output controls

/* base address */
#define MAUDIO_SPECIFIC_ADDRESS	0xffc700000000

/*
 * FW1814/ProjectMix don't use AVC for control. The driver cannot refer to
 * current parameters by asynchronous transaction. The driver is allowed to
 * write transaction so MUST remember the current values.
 */
#define	MAUDIO_CONTROL_OFFSET	0x00700000

/*
 * GAIN for inputs:
 * Write 32bit. upper 16bit for left chennal and lower 16bit for right.
 * The value is between 0x8000(low) to 0x0000(high) as the same as '10.3.1
 * Volume Control' in 'AV/C Audio Subunit Specification 1.0 (1394TA 1999008)'.
 */
#define GAIN_STM_12_IN          0x00
#define GAIN_STM_34_IN          0x04
#define GAIN_ANA_12_OUT         0x08
#define GAIN_ANA_34_OUT         0x0c
#define GAIN_ANA_12_IN          0x10
#define GAIN_ANA_34_IN          0x14
#define GAIN_ANA_56_IN          0x18
#define GAIN_ANA_78_IN          0x1c
#define GAIN_SPDIF_12_IN        0x20
#define GAIN_ADAT_12_IN         0x24
#define GAIN_ADAT_34_IN         0x28
#define GAIN_ADAT_56_IN         0x2c
#define GAIN_ADAT_78_IN         0x30
#define GAIN_AUX_12_OUT         0x34
#define GAIN_HP_12_OUT          0x38
#define GAIN_HP_34_OUT          0x3c

/*
 * LR balance:
 * Write 32 bit, upper 16bit for left channel and lower 16bit for right.
 * The value is between 0x800(L) to 0x7FFE(R) as the same as '10.3.3 LR Balance
 * Control' in 'AV/C Audio Subunit Specification 1.0 (1394TA 1999008)'.
 */
#define LR_ANA_12_IN    0x40
#define LR_ANA_34_IN    0x44
#define LR_ANA_56_IN    0x48
#define LR_ANA_78_IN    0x4c
#define LR_SPDIF_12_IN  0x50
#define LR_ADAT_12_IN   0x54
#define LR_ADAT_34_IN   0x58
#define LR_ADAT_56_IN   0x5c
#define LR_ADAT_78_IN   0x60

/*
 * AUX inputs:
 * This is the same as 'gain' control above.
 */
#define AUX_STM_12_IN   0x64
#define AUX_STM_34_IN   0x68
#define AUX_ANA_12_IN   0x6c
#define AUX_ANA_34_IN   0x70
#define AUX_ANA_56_IN   0x74
#define AUX_ANA_78_IN   0x78
#define AUX_SPDIF_12_IN 0x7c
#define AUX_ADAT_12_IN  0x80
#define AUX_ADAT_34_IN  0x84
#define AUX_ADAT_56_IN  0x88
#define AUX_ADAT_78_IN  0x8c

/*
 * MIXER inputs:
 * There are bit flags. If flag is 0x01, it means on.
 *
 *  MIX_ANA_DIG_IN:
 *  Write 32bits, lower 24bits are used.
 *  [0x 00 UV WX YZ]
 *   U: SPDIF_12 to Mix34
 *   V: SPDIF_12 to Mix12
 *   W: ADAT_12345678 to Mix34
 *   X: ADAT_12345678 to Mix12
 *   Y: Ana_12345678 to Mix34
 *   Z: Ana_12345678 to Mix12
 *  The least significant bit is used for channel 1/2,
 *  the most significant bit is used for channel 7/8.
 * 
 *  MIX_STM_IN:
 *   Write 32bits, lower 4bits are used. upper 2bits for 'from Stm1/2' and lower
 *   for 'from Stm3/4'. Inner the 2bits, most significant bit is for 'to Mix3/4'
 *   and least significant bit is for 'to Mix1/2'.
 */
#define MIX_ANA_DIG_IN	0x90
#define MIX_STM_IN	0x94
/*
 * SRC for output:
 * Write 32bit. There are bit flags. If the flag is 0x01, it means on.
 *
 *  SRC_HP_OUT:
 *  Lower 3bits are used, 'from Aux12', 'from Mix34', 'from
 *  Mix12'.
 *
 *  SRC_ANA_OUT:
 *  Lower 2 bits are used, 'to Ana34', 'to Ana12'. If bit is 0x01, it
 *  means 'from Aux12' else 'From Mix12 (or Mix34)'.
 */
#define SRC_HP_OUT	0x98
#define SRC_ANA_OUT	0x9c
/*
 * FW1814 and ProjectMix gives no way to read its control. So drivers
 * should remember the value for each parameters. Windows driver, after loading
 * firmware, write all parameters just after flushing. 
 */


#define MIXER_OFFSET        0x00700000

#define MIXER_SIZE_SPECIAL 160

/* default parameters loaded by Windows driver */
static unsigned char mixer_init_data[MIXER_SIZE_SPECIAL] = {
	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
	0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,
	0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,  0x7f, 0xfe, 0x80, 0x00,
	0x7f, 0xfe, 0x80, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,
	0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,
	0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,  0x81, 0x00, 0x81, 0x00,
	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x09,  0x00, 0x01, 0x00, 0x01,  0x00, 0x00, 0x00, 0x00
};

int special_set_mixer_init_data(struct snd_bebob *bebob, void *buf, unsigned int size)
{
	return snd_fw_transaction(bebob->unit, TCODE_WRITE_BLOCK_REQUEST,
				  MAUDIO_SPECIFIC_ADDRESS + MIXER_OFFSET,
				  buf, size, 0);
}

Test command to blink all LEDs on front panel

/*
 * Just after loading Windows driver issues following command to blink all the leds
 *
static int
snd_bebob_maudio_special_indication_test(struct snd_bebob *bebob)
{
	u8 buf[8];

	buf[0] = 0x00;	/* control */
	buf[1] = 0xff;	/* unit */
	buf[2] = 0x00;	/* vendor dependent command */
	buf[3] = 0x02;	/* unknown */
	buf[4] = 0x00;	/* unknown */
	buf[5] = 0x00;	/* unknown */
	buf[6] = 0x00;	/* unknown */
	buf[7] = 0x00;	/* unknown */

	return fcp_avc_transaction(bebob->unit, buf, 8, buf, 8, 0);
}

Clock parameters control

/*
 * clk_src: 0x00:internal without digital in, 0x01:external, 0x02:word_clock, 0x03:internal with digital in
 * in_dig_fmt: 0x00:S/PDIF, 0x01:ADAT
 * out_dig_fmt: 0x00:S/PDIF, 0x01:ADAT
 * clk_lock: 0x00:unlocked, 0x01:locked
 */
static int
set_clock_params(struct snd_bebob *bebob, int clk_src,
		 int in_dig_fmt, int out_dig_fmt, int clk_lock)
{
	int err;
	u8 *buf;

	buf = kmalloc(12, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;

	buf[0]  = 0x00;		/* CONTROL */
	buf[1]  = 0xff;		/* UNIT */
	buf[2]  = 0x00;		/* vendor dependent */
	buf[3]  = 0x04;
	buf[4]  = 0x00;
	buf[5]  = 0x04;			/* has 4 parameters */
	buf[6]  = 0xff & clk_src;	/* clock source */
	buf[7]  = 0xff & in_dig_fmt;	/* input digital format */
	buf[8]  = 0xff & out_dig_fmt;	/* output digital format */
	buf[9]  = 0xff & clk_lock;	/* lock these settings */
	buf[10] = 0x00;		/* padding  */
	buf[11] = 0x00;		/* padding */

	err = fcp_avc_transaction(bebob->unit, buf, 8, buf, 8, 0);
	if (err < 0)
		goto end;
	if ((err < 6) || (buf[0] != 0x09)) {
		dev_err(&bebob->unit->device,
			"failed to set clock params\n");
		err = -EIO;
		goto end;
	}

	err = 0;
end:
	kfree(buf);
	return err;
}

Digital interface control

For this purpose, selector function block command in AV/C Audio subunit specification.

/*
 * function block id: 0x04
 * dig_iface: 0x00:Optical, 0x01:Coaxial
 */

Reverse engineering of Windows driver timing digram

1. Driver polls for meter data every 100 ms reading
#define METER_SIZE_SPECIAL 84 /* with sync info */

bytes from

#define METER_OFFSET 0x00600000

2. Any FCP transaction (except 'lock pll' and 'set sampling rate') takes less then 100 ms

3. Any regular read/write may happen at any time (e.g. mixer controls)

4. The most interesting part: set sampling rate. Here is the part of the log with timings

    ffc1 ffff f000 0b00         8  OUT    00 ff 18 00  90 03 ffff                            ........          2.8ms 80.1.0 15:06:58.773  mafw
    0000 ffff f000 0d00         8  IN     0f ff 18 00  90 03 ffff                            ........          106ms 81.1.0 15:06:58.883  mafw
    0000 ffff f000 0d00         8  IN     09 ff 18 00  90 03 ffff                            ........          132ms 82.1.0 15:06:59.013  mafw

this reply usually arrives after about 150 ms

    ffc1 ffff f000 0b00         8  OUT    00 ff 19 00  90 03 ffff                            ........          1.4ms 83.1.0 15:06:59.013  mafw
    0000 ffff f000 0d00         8  IN     0f ff 19 00  90 03 ffff                            ........           91ms 84.1.0 15:06:59.103  mafw
    0000 ffff f000 0d00         8  IN     09 ff 19 00  90 03 ffff                            ........          332ms 85.1.0 15:06:59.443  mafw

reply to this FCP request arrived in 332 ms. and the next access to the device happens only after 1 sec!!!

   46    ffc1 ffc7 0060 0000        84  IN     00 00 00 00  00 05 00 0100 1a 00 1b  00 1a 00 1a  ................  1.0sc 86.1.0 15:07:00.493  mafw
                                               00 18 00 18  00 00 00 0000 00 00 00  00 00 00 00  ................ 86.1.16
                                               00 00 00 00  00 00 00 0000 00 00 00  00 00 00 00  ................ 86.1.32
                                               00 00 00 00  00 00 00 0000 00 00 00  00 00 00 00  ................ 86.1.48
                                               00 00 00 00  00 00 00 0000 00 00 00  00 00 00 00  ................ 86.1.64
                                               00 00 03 01                         ....                           86.1.80 

Logs with firewire_ohci and debug=1 option

At releasing connections/resources for both direction:
[27200.724273] firewire_ohci 0000:0c:06.0: AT spd 2 tl 28, ffc0 -> ffc1, ack_pending , Lk req, fffff0000984 8,2
[27200.724921] firewire_ohci 0000:0c:06.0: AR spd 2 tl 28, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27200.725037] firewire_ohci 0000:0c:06.0: AT spd 0 tl 29, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27200.725598] firewire_ohci 0000:0c:06.0: AR spd 2 tl 29, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27200.725714] firewire_ohci 0000:0c:06.0: AT spd 0 tl 2a, ffc0 -> ffc1, ack_pending , Lk req, fffff0000220 8,2
[27202.727199] firewire_ohci 0000:0c:06.0: AT spd 0 tl 2b, ffc0 -> ffc1, ack_pending , Lk req, fffff0000220 8,2
[27202.727735] firewire_ohci 0000:0c:06.0: AR spd 2 tl 2b, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27202.727858] firewire_ohci 0000:0c:06.0: AT spd 2 tl 2c, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27204.750950] firewire_ohci 0000:0c:06.0: AT spd 2 tl 2d, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27206.777677] firewire_ohci 0000:0c:06.0: AT spd 2 tl 2e, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27208.779327] snd-bebob fw1.0: transaction failed: timeout
[27208.779333] snd-bebob fw1.0: oPCR0: plug is still connected
(The device handle a first operation for oPCR0 but not respond.)

At releasing connections/resources for both direction:
[27603.200092] firewire_ohci 0000:0c:06.0: AT spd 2 tl 02, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27603.200455] firewire_ohci 0000:0c:06.0: AR spd 2 tl 02, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27603.200629] firewire_ohci 0000:0c:06.0: AT spd 0 tl 03, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27605.203315] firewire_ohci 0000:0c:06.0: AT spd 0 tl 04, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27605.203962] firewire_ohci 0000:0c:06.0: AR spd 2 tl 04, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27605.204077] firewire_ohci 0000:0c:06.0: AT spd 0 tl 05, ffc0 -> ffc1, ack_pending , Lk req, fffff0000220 8,2
[27605.204507] firewire_ohci 0000:0c:06.0: AR spd 2 tl 05, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27605.204569] snd-bebob fw1.0: isochronous resource deallocation failed
(The device handle a first operation for CSR_CHANNELS_AVAILABLE_HI but not respond.)

At keeping resources and establising connections:
[27212.950366] firewire_ohci 0000:0c:06.0: AT spd 0 tl 35, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27212.950922] firewire_ohci 0000:0c:06.0: AR spd 2 tl 35, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.951060] firewire_ohci 0000:0c:06.0: AT spd 0 tl 36, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27212.951505] firewire_ohci 0000:0c:06.0: AR spd 2 tl 36, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.951590] firewire_ohci 0000:0c:06.0: AT spd 0 tl 37, ffc0 -> ffc1, ack_pending , Lk req, fffff0000220 8,2
[27212.952101] firewire_ohci 0000:0c:06.0: AR spd 2 tl 37, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.952220] firewire_ohci 0000:0c:06.0: AT spd 2 tl 38, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27212.952568] firewire_ohci 0000:0c:06.0: AR spd 2 tl 38, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.952715] firewire_ohci 0000:0c:06.0: AT spd 2 tl 39, ffc0 -> ffc1, ack_pending , Lk req, fffff0000904 8,2
[27212.953044] firewire_ohci 0000:0c:06.0: AR spd 2 tl 39, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.953178] firewire_ohci 0000:0c:06.0: AT spd 0 tl 3a, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27212.953504] firewire_ohci 0000:0c:06.0: AR spd 2 tl 3a, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.953588] firewire_ohci 0000:0c:06.0: AT spd 0 tl 3b, ffc0 -> ffc1, ack_pending , Lk req, fffff0000224 8,2
[27212.954017] firewire_ohci 0000:0c:06.0: AR spd 2 tl 3b, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.954077] firewire_ohci 0000:0c:06.0: AT spd 0 tl 3c, ffc0 -> ffc1, ack_pending , Lk req, fffff0000220 8,2
[27212.954364] firewire_ohci 0000:0c:06.0: AR spd 2 tl 3c, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27212.954429] firewire_ohci 0000:0c:06.0: AT spd 2 tl 3d, ffc0 -> ffc1, ack_pending , Lk req, fffff0000984 8,2
[27214.980602] firewire_ohci 0000:0c:06.0: AT spd 2 tl 3e, ffc0 -> ffc1, ack_pending , Lk req, fffff0000984 8,2
[27214.981135] firewire_ohci 0000:0c:06.0: AR spd 2 tl 3e, ffc1 -> ffc0, ack_complete, Lk resp 4,2
[27214.981195] snd-bebob fw1.0: iPCR0: plug is already in use
(The device handle a first operation for iPCR0 but not respond.)