All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
To: clemens@ladisch.de, tiwai@suse.de, perex@perex.cz
Cc: alsa-devel@alsa-project.org,
	linux1394-devel@lists.sourceforge.net, ffado-devel@lists.sf.net
Subject: [PATCH 30/44] bebob: Add commands and connections/streams management
Date: Fri, 21 Mar 2014 20:10:15 +0900	[thread overview]
Message-ID: <1395400229-22957-31-git-send-email-o-takashi@sakamocchi.jp> (raw)
In-Reply-To: <1395400229-22957-1-git-send-email-o-takashi@sakamocchi.jp>

This commit adds management functionality for connections and streams.
BeBoB uses CMP to manage connections and uses AMDTP for streams.

This commit also adds some BridgeCo's AV/C extension commands. There are many
BridgeCo's AV/C extension commands but this commit adds below commands to get
device's capability and status:

 1.Extended Plug Info commands
  - Plug Channel Position Specific Data
  - Plug Type Specific Data
  - Cluster(Section) Info Specific Data
  - Plug Input Specific Data
 2.Extended Stream Format Information commands
  - Extended Stream Format Information Command - Single Request

For Extended Plug Info commands for Cluster Info Specific Data, I pick up
'section' instead of 'cluster' from document to prevent from misunderstanding
because 'cluster' is also used in IEC 61883-6.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/bebob/Makefile        |   2 +-
 sound/firewire/bebob/bebob.c         |  10 +
 sound/firewire/bebob/bebob.h         | 117 +++++
 sound/firewire/bebob/bebob_command.c | 232 ++++++++++
 sound/firewire/bebob/bebob_stream.c  | 805 +++++++++++++++++++++++++++++++++++
 5 files changed, 1165 insertions(+), 1 deletion(-)
 create mode 100644 sound/firewire/bebob/bebob_command.c
 create mode 100644 sound/firewire/bebob/bebob_stream.c

diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile
index c6f0141..5cece62 100644
--- a/sound/firewire/bebob/Makefile
+++ b/sound/firewire/bebob/Makefile
@@ -1,2 +1,2 @@
-snd-bebob-objs := bebob.o
+snd-bebob-objs := bebob_command.o bebob_stream.o bebob.o
 obj-m += snd-bebob.o
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index a2ced1a..0c113b6 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -159,6 +159,14 @@ bebob_probe(struct fw_unit *unit,
 	if (err < 0)
 		goto error;
 
+	err = snd_bebob_stream_discover(bebob);
+	if (err < 0)
+		goto error;
+
+	err = snd_bebob_stream_init_duplex(bebob);
+	if (err < 0)
+		goto error;
+
 	err = snd_card_register(card);
 	if (err < 0)
 		goto error;
@@ -177,12 +185,14 @@ bebob_update(struct fw_unit *unit)
 {
 	struct snd_bebob *bebob = dev_get_drvdata(&unit->device);
 	fcp_bus_reset(bebob->unit);
+	snd_bebob_stream_update_duplex(bebob);
 }
 
 
 static void bebob_remove(struct fw_unit *unit)
 {
 	struct snd_bebob *bebob = dev_get_drvdata(&unit->device);
+	snd_bebob_stream_destroy_duplex(bebob);
 	snd_card_disconnect(bebob->card);
 	snd_card_free_when_closed(bebob->card);
 }
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index 173f4558..550ccdc 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -23,11 +23,25 @@
 
 #include "../lib.h"
 #include "../fcp.h"
+#include "../packets-buffer.h"
+#include "../iso-resources.h"
+#include "../amdtp.h"
+#include "../cmp.h"
 
 /* basic register addresses on DM1000 */
 #define BEBOB_ADDR_REG_INFO	0xffffc8020000
 #define BEBOB_ADDR_REG_REQ	0xffffc8021000
 
+struct snd_bebob;
+
+#define SND_BEBOB_STRM_FMT_ENTRIES	7
+struct snd_bebob_stream_formation {
+	unsigned int pcm;
+	unsigned int midi;
+};
+/* this is a lookup table for index of stream formations */
+extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES];
+
 struct snd_bebob {
 	struct snd_card *card;
 	struct fw_unit *unit;
@@ -35,6 +49,23 @@ struct snd_bebob {
 
 	struct mutex mutex;
 	spinlock_t lock;
+
+	unsigned int midi_input_ports;
+	unsigned int midi_output_ports;
+
+	struct cmp_connection out_conn;
+	struct amdtp_stream tx_stream;
+	struct cmp_connection in_conn;
+	struct amdtp_stream rx_stream;
+	unsigned int capture_substreams;
+	unsigned int playback_substreams;
+
+	struct snd_bebob_stream_formation
+		tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
+	struct snd_bebob_stream_formation
+		rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
+
+	int sync_input_plug;
 };
 
 static inline int
@@ -53,6 +84,92 @@ snd_bebob_read_quad(struct fw_unit *unit, u64 addr, u32 *buf)
 				  (void *)buf, sizeof(u32), 0);
 }
 
+/*
+ * AVC command extensions, AV/C Unit and Subunit, Revision 17
+ * (Nov 2003, BridgeCo)
+ */
+#define	AVC_BRIDGECO_ADDR_BYTES	6
+enum avc_bridgeco_plug_dir {
+	AVC_BRIDGECO_PLUG_DIR_IN	= 0x00,
+	AVC_BRIDGECO_PLUG_DIR_OUT	= 0x01
+};
+enum avc_bridgeco_plug_mode {
+	AVC_BRIDGECO_PLUG_MODE_UNIT		= 0x00,
+	AVC_BRIDGECO_PLUG_MODE_SUBUNIT		= 0x01,
+	AVC_BRIDGECO_PLUG_MODE_FUNCTION_BLOCK	= 0x02
+};
+enum avc_bridgeco_plug_unit {
+	AVC_BRIDGECO_PLUG_UNIT_ISOC	= 0x00,
+	AVC_BRIDGECO_PLUG_UNIT_EXT	= 0x01,
+	AVC_BRIDGECO_PLUG_UNIT_ASYNC	= 0x02
+};
+enum avc_bridgeco_plug_type {
+	AVC_BRIDGECO_PLUG_TYPE_ISOC	= 0x00,
+	AVC_BRIDGECO_PLUG_TYPE_ASYNC	= 0x01,
+	AVC_BRIDGECO_PLUG_TYPE_MIDI	= 0x02,
+	AVC_BRIDGECO_PLUG_TYPE_SYNC	= 0x03,
+	AVC_BRIDGECO_PLUG_TYPE_ANA	= 0x04,
+	AVC_BRIDGECO_PLUG_TYPE_DIG	= 0x05
+};
+static inline void
+avc_bridgeco_fill_unit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES],
+			    enum avc_bridgeco_plug_dir dir,
+			    enum avc_bridgeco_plug_unit unit,
+			    unsigned int pid)
+{
+	buf[0] = 0xff;	/* Unit */
+	buf[1] = dir;
+	buf[2] = AVC_BRIDGECO_PLUG_MODE_UNIT;
+	buf[3] = unit;
+	buf[4] = 0xff & pid;
+	buf[5] = 0xff;	/* reserved */
+}
+static inline void
+avc_bridgeco_fill_subunit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES],
+			       unsigned int mode,
+			       enum avc_bridgeco_plug_dir dir,
+			       unsigned int pid)
+{
+	buf[0] = 0xff & mode;	/* Subunit */
+	buf[1] = dir;
+	buf[2] = AVC_BRIDGECO_PLUG_MODE_SUBUNIT;
+	buf[3] = 0xff & pid;
+	buf[4] = 0xff;	/* reserved */
+	buf[5] = 0xff;	/* reserved */
+}
+int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
+				 u8 add[AVC_BRIDGECO_ADDR_BYTES],
+				 u8 *buf, unsigned int len);
+int avc_bridgeco_get_plug_type(struct fw_unit *unit,
+			       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+			       enum avc_bridgeco_plug_type *type);
+int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
+				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				       unsigned int section_id, u8 *ctype);
+int avc_bridgeco_get_plug_input(struct fw_unit *unit,
+				u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				u8 input[7]);
+int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
+				   u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				   unsigned int entryid, u8 *buf,
+				   unsigned int *len);
+
+/* for AMDTP streaming */
+int snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *rate);
+int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate);
+int snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob,
+					  bool *internal);
+int snd_bebob_stream_discover(struct snd_bebob *bebob);
+int snd_bebob_stream_map(struct snd_bebob *bebob,
+			 struct amdtp_stream *stream);
+int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob,
+				  struct amdtp_stream *stream,
+				   unsigned int sampling_rate);
+int snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
+void snd_bebob_stream_update_duplex(struct snd_bebob *bebob);
+void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
+
 #define SND_BEBOB_DEV_ENTRY(vendor, model) \
 { \
 	.match_flags	= IEEE1394_MATCH_VENDOR_ID | \
diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c
new file mode 100644
index 0000000..ec7031a
--- /dev/null
+++ b/sound/firewire/bebob/bebob_command.c
@@ -0,0 +1,232 @@
+/*
+ * bebob_command.c - driver for BeBoB based devices
+ *
+ * Copyright (c) 2013 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./bebob.h"
+
+static inline void
+avc_bridgeco_fill_command_base(u8 *buf, unsigned int ctype, unsigned int opcode,
+			       unsigned int subfunction,
+			       u8 addr[AVC_BRIDGECO_ADDR_BYTES])
+{
+	buf[0] = 0x7 & ctype;
+	buf[1] = addr[0];
+	buf[2] = 0xff & opcode;
+	buf[3] = 0xff & subfunction;
+	buf[4] = addr[1];
+	buf[5] = addr[2];
+	buf[6] = addr[3];
+	buf[7] = addr[4];
+	buf[8] = addr[5];
+}
+
+int avc_bridgeco_get_plug_type(struct fw_unit *unit,
+			       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+			       enum avc_bridgeco_plug_type *type)
+{
+	u8 *buf;
+	int err;
+
+	buf = kzalloc(12, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* status for plug info with bridgeco extension */
+	avc_bridgeco_fill_command_base(buf, 0x01, 0x02, 0xc0, addr);
+	buf[9]  = 0x00;		/* info type is 'plug type' */
+	buf[10] = 0xff;		/* plug type in response */
+
+	/* do transaction and check buf[1-7,9] are the same against command */
+	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
+				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+				  BIT(6) | BIT(7) | BIT(9));
+	if (err > 0 && err < 8)
+		err = -EIO;
+	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+		err = -ENOSYS;
+	else if (buf[0] == 0x0a) /* REJECTED */
+		err = -EINVAL;
+	else if (buf[0] == 0x0b) /* IN TRANSITION */
+		err = -EAGAIN;
+	if (err < 0)
+		goto end;
+
+	*type = buf[10];
+	err = 0;
+end:
+	kfree(buf);
+	return err;
+}
+
+int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit,
+				 u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				 u8 *buf, unsigned int len)
+{
+	int err;
+
+	/* check given buffer */
+	if ((buf == NULL) || (len < 256)) {
+		err = -EINVAL;
+		goto end;
+	}
+
+	/* status for plug info with bridgeco extension */
+	avc_bridgeco_fill_command_base(buf, 0x01, 0x02, 0xc0, addr);
+
+	/* info type is 'channel position' */
+	buf[9] = 0x03;
+
+	/* do transaction and check buf[1-7,9] are the same */
+	err = fcp_avc_transaction(unit, buf, 12, buf, 256,
+				  BIT(1) | BIT(2) | BIT(3) | BIT(4) |
+				  BIT(5) | BIT(6) | BIT(7) | BIT(9));
+	if (err > 0 && err < 8)
+		err = -EIO;
+	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+		err = -ENOSYS;
+	else if (buf[0] == 0x0a) /* REJECTED */
+		err = -EINVAL;
+	else if (buf[0] == 0x0b) /* IN TRANSITION */
+		err = -EAGAIN;
+	if (err < 0)
+		goto end;
+
+	/* strip command header */
+	memmove(buf, buf + 10, err - 10);
+	err = 0;
+end:
+	return err;
+}
+
+int avc_bridgeco_get_plug_section_type(struct fw_unit *unit,
+				       u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				       unsigned int section_id, u8 *type)
+{
+	u8 *buf;
+	int err;
+
+	/* section info includes charactors but this module don't need it */
+	buf = kzalloc(12, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* status for plug info with bridgeco extension */
+	avc_bridgeco_fill_command_base(buf, 0x01, 0x02, 0xc0, addr);
+
+	buf[9] = 0x07;		/* info type is 'section info' */
+	buf[10] = 0xff & (section_id + 1);	/* section id */
+	buf[11] = 0x00;		/* type in response */
+
+	/* do transaction and check buf[1-7,9,10] are the same */
+	err = fcp_avc_transaction(unit, buf, 12, buf, 12,
+				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+				  BIT(6) | BIT(7) | BIT(9) | BIT(10));
+	if (err > 0 && err < 8)
+		err = -EIO;
+	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+		err = -ENOSYS;
+	else if (buf[0] == 0x0a) /* REJECTED */
+		err = -EINVAL;
+	else if (buf[0] == 0x0b) /* IN TRANSITION */
+		err = -EAGAIN;
+	if (err < 0)
+		goto end;
+
+	*type = buf[11];
+	err = 0;
+end:
+	kfree(buf);
+	return err;
+}
+
+int avc_bridgeco_get_plug_input(struct fw_unit *unit,
+				u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7])
+{
+	int err;
+	u8 *buf;
+
+	buf = kzalloc(18, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* status for plug info with bridgeco extension */
+	avc_bridgeco_fill_command_base(buf, 0x01, 0x02, 0xc0, addr);
+
+	/* info type is 'Plug Input Specific Data' */
+	buf[9] = 0x05;
+
+	/* do transaction and check buf[1-7] are the same */
+	err = fcp_avc_transaction(unit, buf, 16, buf, 16,
+				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+				  BIT(6) | BIT(7));
+	if (err > 0 && err < 8)
+		err = -EIO;
+	else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+		err = -ENOSYS;
+	else if (buf[0] == 0x0a) /* REJECTED */
+		err = -EINVAL;
+	else if (buf[0] == 0x0b) /* IN TRANSITION */
+		err = -EAGAIN;
+	if (err < 0)
+		goto end;
+
+	memcpy(input, buf + 10, 5);
+end:
+	kfree(buf);
+	return err;
+}
+
+int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
+				   u8 addr[AVC_BRIDGECO_ADDR_BYTES],
+				   unsigned int entryid, u8 *buf,
+				   unsigned int *len)
+{
+	int err;
+
+	/* check given buffer */
+	if ((buf == NULL) || (*len < 12)) {
+		err = -EINVAL;
+		goto end;
+	}
+
+	/* status for plug info with bridgeco extension */
+	avc_bridgeco_fill_command_base(buf, 0x01, 0x2f, 0xc1, addr);
+
+	buf[9] = 0xff;			/* stream status in response */
+	buf[10] = 0xff & entryid;	/* entry ID */
+
+	/* do transaction and check buf[1-7,10] are the same against command */
+	err = fcp_avc_transaction(unit, buf, 12, buf, *len,
+				  BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+				  BIT(6) | BIT(7) | BIT(10));
+	if (err < 0)
+		goto end;
+
+	/* reach the end of entries */
+	if (buf[0] == 0x0a) {
+		err = 0;
+		*len = 0;
+		goto end;
+	} else if (buf[0] != 0x0c) {
+		err = -EINVAL;
+	/* the header of this command is 11 bytes */
+	} else if (err < 12) {
+		err = -EIO;
+	} else if (buf[10] != entryid) {
+		err = -EIO;
+	}
+
+	if (err < 0)
+		goto end;
+
+	/* strip command header */
+	memmove(buf, buf + 11, err - 11);
+	*len = err - 11;
+	err = 0;
+end:
+	return err;
+}
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
new file mode 100644
index 0000000..9375454
--- /dev/null
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -0,0 +1,805 @@
+/*
+ * bebob_stream.c - a part of driver for BeBoB based devices
+ *
+ * Copyright (c) 2013 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./bebob.h"
+
+#define CALLBACK_TIMEOUT	1000
+
+/*
+ * NOTE;
+ * For BeBoB streams, Both of input and output CMP connection are important.
+ *
+ * For most devices, each CMP connection starts to transmit/receive a
+ * corresponding streams. But for a few devices, both of CMP connection needs
+ * to start transmitting stream. An example is 'M-Audio Firewire 410'.
+ */
+
+/* 128 is an arbitrary length but it seems to be enough */
+#define FORMAT_MAXIMUM_LENGTH 128
+
+const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES] = {
+	[0] = 32000,
+	[1] = 44100,
+	[2] = 48000,
+	[3] = 88200,
+	[4] = 96000,
+	[5] = 176400,
+	[6] = 192000,
+};
+
+/*
+ * See: Table 51: Extended Stream Format Info ‘Sampling Frequency’
+ * in Additional AVC commands (Nov 2003, BridgeCo)
+ */
+static const unsigned int bridgeco_freq_table[] = {
+	[0] = 0x02,
+	[1] = 0x03,
+	[2] = 0x04,
+	[3] = 0x0a,
+	[4] = 0x05,
+	[5] = 0x06,
+	[6] = 0x07,
+};
+
+static unsigned int
+get_formation_index(unsigned int rate)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(snd_bebob_rate_table); i++) {
+		if (snd_bebob_rate_table[i] == rate)
+			return i;
+	}
+	return -1;
+}
+
+int
+snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate)
+{
+	unsigned int tx_rate, rx_rate, trials;
+	int err;
+
+	trials = 0;
+	do {
+		err = avc_general_get_sig_fmt(bebob->unit, &tx_rate,
+					      AVC_GENERAL_PLUG_DIR_OUT, 0);
+	} while (err == -EAGAIN && ++trials < 3);
+	if (err < 0)
+		goto end;
+
+	trials = 0;
+	do {
+		err = avc_general_get_sig_fmt(bebob->unit, &rx_rate,
+					      AVC_GENERAL_PLUG_DIR_IN, 0);
+	} while (err == -EAGAIN && ++trials < 3);
+	if (err < 0)
+		goto end;
+
+	*curr_rate = rx_rate;
+	if (rx_rate == tx_rate)
+		goto end;
+
+	/* synchronize receive stream rate to transmit stream rate */
+	err = avc_general_set_sig_fmt(bebob->unit, rx_rate,
+				      AVC_GENERAL_PLUG_DIR_IN, 0);
+end:
+	if (err < 0)
+		dev_err(&bebob->unit->device,
+			"failed to get sampling rate: %d\n", err);
+	return err;
+}
+
+int
+snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate)
+{
+	int err;
+
+	err = avc_general_set_sig_fmt(bebob->unit, rate,
+				      AVC_GENERAL_PLUG_DIR_OUT, 0);
+	if (err < 0)
+		goto end;
+
+	err = avc_general_set_sig_fmt(bebob->unit, rate,
+				      AVC_GENERAL_PLUG_DIR_IN, 0);
+end:
+	if (err < 0)
+		dev_err(&bebob->unit->device,
+			"failed to set sampling rate: %d\n", err);
+	return err;
+}
+
+int
+snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
+{
+	u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
+	int err = 0;
+
+	*internal = false;
+
+	/*
+	 * 1.The device don't support for switching source of clock
+	 *   then assumed to use internal clock always
+	 */
+	if (bebob->sync_input_plug < 0) {
+		*internal = true;
+		goto end;
+	}
+
+	/*
+	 * 2.The device supports to switch source of clock by an usual way.
+	 *   Let's check input for 'Music Sub Unit Sync Input' plug.
+	 */
+	avc_bridgeco_fill_subunit_addr(addr, 0x60, AVC_BRIDGECO_PLUG_DIR_IN,
+				       bebob->sync_input_plug);
+	err = avc_bridgeco_get_plug_input(bebob->unit, addr, input);
+	if (err < 0)
+		goto end;
+
+	/*
+	 * If there are no input plugs, all of fields are 0xff.
+	 * Here check the first field. This field is used for direction.
+	 */
+	if (input[0] == 0xff) {
+		*internal = true;
+		goto end;
+	}
+
+	/*
+	 * If source of clock is internal CSR, Music Sub Unit Sync Input is
+	 * a destination of Music Sub Unit Sync Output.
+	 */
+	*internal = ((input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) &&
+		     (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT) &&
+		     (input[2] == 0x0c) &&
+		     (input[3] == 0x00));
+end:
+	return err;
+}
+
+static unsigned int
+map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
+{
+	unsigned int sec, sections, ch, channels;
+	unsigned int pcm, midi, location;
+	unsigned int stm_pos, sec_loc, pos;
+	u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type;
+	enum avc_bridgeco_plug_dir dir;
+	int err;
+
+	/*
+	 * The length of return value of this command cannot be expected. Here
+	 * use the maximum length of FCP.
+	 */
+	buf = kzalloc(256, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	if (s == &bebob->tx_stream)
+		dir = AVC_BRIDGECO_PLUG_DIR_OUT;
+	else
+		dir = AVC_BRIDGECO_PLUG_DIR_IN;
+
+	avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
+	err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256);
+	if (err < 0)
+		goto end;
+	pos = 0;
+
+	/* positions in I/O buffer */
+	pcm = 0;
+	midi = 0;
+
+	/* the number of sections in AMDTP packet */
+	sections = buf[pos++];
+
+	for (sec = 0; sec < sections; sec++) {
+		/* type of this section */
+		avc_bridgeco_fill_unit_addr(addr, dir,
+					    AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
+		err = avc_bridgeco_get_plug_section_type(bebob->unit, addr,
+							 sec, &type);
+		if (err < 0)
+			goto end;
+		/* NoType */
+		if (type == 0xff) {
+			err = -ENOSYS;
+			goto end;
+		}
+
+		/* the number of channels in this section */
+		channels = buf[pos++];
+
+		for (ch = 0; ch < channels; ch++) {
+			/* position of this channel in AMDTP packet */
+			stm_pos = buf[pos++] - 1;
+			/* location of this channel in this section */
+			sec_loc = buf[pos++] - 1;
+
+			switch (type) {
+			/* for MIDI conformant data channel */
+			case 0x0a:
+				/* AMDTP_MAX_CHANNELS_FOR_MIDI is 1. */
+				if ((midi > 0) && (stm_pos != midi)) {
+					err = -ENOSYS;
+					goto end;
+				}
+				s->midi_position = stm_pos;
+				midi = stm_pos;
+				break;
+			/* for PCM data channel */
+			case 0x01:	/* Headphone */
+			case 0x02:	/* Microphone */
+			case 0x03:	/* Line */
+			case 0x04:	/* SPDIF */
+			case 0x05:	/* ADAT */
+			case 0x06:	/* TDIF */
+			case 0x07:	/* MADI */
+			/* for undefined/changeable signal  */
+			case 0x08:	/* Analog */
+			case 0x09:	/* Digital */
+			default:
+				location = pcm + sec_loc;
+				if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) {
+					err = -ENOSYS;
+					goto end;
+				}
+				s->pcm_positions[location] = stm_pos;
+				break;
+			}
+		}
+
+		if (type != 0x0a)
+			pcm += channels;
+		else
+			midi += channels;
+	}
+end:
+	kfree(buf);
+	return err;
+}
+
+static int
+init_both_connections(struct snd_bebob *bebob)
+{
+	int err;
+
+	err = cmp_connection_init(&bebob->in_conn,
+				  bebob->unit, CMP_INPUT, 0);
+	if (err < 0)
+		goto end;
+
+	err = cmp_connection_init(&bebob->out_conn,
+				  bebob->unit, CMP_OUTPUT, 0);
+	if (err < 0)
+		cmp_connection_destroy(&bebob->in_conn);
+end:
+	return err;
+}
+
+static int
+check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
+{
+	struct cmp_connection *conn;
+	bool used;
+	int err;
+
+	if (s == &bebob->tx_stream)
+		conn = &bebob->out_conn;
+	else
+		conn = &bebob->in_conn;
+
+	err = cmp_connection_check_used(conn, &used);
+	if ((err >= 0) && used && !amdtp_stream_running(s)) {
+		dev_err(&bebob->unit->device,
+			"Connection established by others: %cPCR[%d]\n",
+			(conn->direction == CMP_OUTPUT) ? 'o' : 'i',
+			conn->pcr_index);
+		err = -EBUSY;
+	}
+
+	return err;
+}
+
+static int
+make_both_connections(struct snd_bebob *bebob, unsigned int rate)
+{
+	int index, pcm_channels, midi_channels, err;
+
+	/* confirm params for both streams */
+	index = get_formation_index(rate);
+	pcm_channels = bebob->tx_stream_formations[index].pcm;
+	midi_channels = bebob->tx_stream_formations[index].midi;
+	amdtp_stream_set_parameters(&bebob->tx_stream,
+				    rate, pcm_channels, midi_channels * 8);
+	pcm_channels = bebob->rx_stream_formations[index].pcm;
+	midi_channels = bebob->rx_stream_formations[index].midi;
+	amdtp_stream_set_parameters(&bebob->rx_stream,
+				    rate, pcm_channels, midi_channels * 8);
+
+	/* establish connections for both streams */
+	err = cmp_connection_establish(&bebob->out_conn,
+			amdtp_stream_get_max_payload(&bebob->tx_stream));
+	if (err < 0)
+		goto end;
+	err = cmp_connection_establish(&bebob->in_conn,
+			amdtp_stream_get_max_payload(&bebob->rx_stream));
+	if (err < 0)
+		cmp_connection_break(&bebob->out_conn);
+end:
+	return err;
+}
+
+static void
+break_both_connections(struct snd_bebob *bebob)
+{
+	cmp_connection_break(&bebob->in_conn);
+	cmp_connection_break(&bebob->out_conn);
+}
+
+static void
+destroy_both_connections(struct snd_bebob *bebob)
+{
+	break_both_connections(bebob);
+
+	cmp_connection_destroy(&bebob->in_conn);
+	cmp_connection_destroy(&bebob->out_conn);
+}
+
+static int
+get_roles(struct snd_bebob *bebob, enum cip_flags *sync_mode,
+	  struct amdtp_stream **master, struct amdtp_stream **slave)
+{
+	/* currently this module doesn't support SYT-Match mode */
+	*sync_mode = CIP_SYNC_TO_DEVICE;
+	*master = &bebob->tx_stream;
+	*slave = &bebob->rx_stream;
+
+	return 0;
+}
+
+static int
+start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream,
+	     unsigned int rate)
+{
+	struct cmp_connection *conn;
+	int err = 0;
+
+	if (stream == &bebob->rx_stream)
+		conn = &bebob->in_conn;
+	else
+		conn = &bebob->out_conn;
+
+	/* channel mapping */
+	err = map_data_channels(bebob, stream);
+	if (err < 0)
+		goto end;
+
+	/* start amdtp stream */
+	err = amdtp_stream_start(stream,
+				 conn->resources.channel,
+				 conn->speed);
+end:
+	return err;
+}
+
+int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
+{
+	int err;
+
+	err = init_both_connections(bebob);
+	if (err < 0)
+		goto end;
+
+	err = amdtp_stream_init(&bebob->tx_stream, bebob->unit,
+				AMDTP_IN_STREAM, CIP_BLOCKING);
+	if (err < 0) {
+		destroy_both_connections(bebob);
+		goto end;
+	}
+
+	err = amdtp_stream_init(&bebob->rx_stream, bebob->unit,
+				AMDTP_OUT_STREAM, CIP_BLOCKING);
+	if (err < 0) {
+		amdtp_stream_destroy(&bebob->tx_stream);
+		destroy_both_connections(bebob);
+	}
+end:
+	return err;
+}
+
+int snd_bebob_stream_start_duplex(struct snd_bebob *bebob,
+				  struct amdtp_stream *request,
+				  unsigned int rate)
+{
+	struct amdtp_stream *master, *slave;
+	enum cip_flags sync_mode;
+	unsigned int curr_rate;
+	bool slave_flag;
+	int err;
+
+	mutex_lock(&bebob->mutex);
+
+	err = get_roles(bebob, &sync_mode, &master, &slave);
+	if (err < 0)
+		goto end;
+
+	/*
+	 * Considering JACK/FFADO streaming:
+	 * TODO: This can be removed hwdep functionality becomes popular.
+	 */
+	err = check_connection_used_by_others(bebob, master);
+	if (err < 0)
+		goto end;
+
+	/* need to touch slave stream */
+	slave_flag = (request == slave) || amdtp_stream_running(slave);
+
+	/* packet queueing error */
+	if (amdtp_streaming_error(master)) {
+		amdtp_stream_stop(master);
+		amdtp_stream_stop(slave);
+	}
+	if (amdtp_streaming_error(slave))
+		amdtp_stream_stop(slave);
+
+	/* stop streams if rate is different */
+	err = snd_bebob_stream_get_rate(bebob, &curr_rate);
+	if (err < 0)
+		goto end;
+	if (rate == 0)
+		rate = curr_rate;
+	if (rate != curr_rate) {
+		amdtp_stream_stop(master);
+		amdtp_stream_stop(slave);
+		break_both_connections(bebob);
+	}
+
+	/* master should be always running */
+	if (!amdtp_stream_running(master)) {
+		amdtp_stream_set_sync(sync_mode, master, slave);
+
+		/*
+		 * NOTE:
+		 * If establishing connections at first, Yamaha GO46
+		 * (and maybe Terratec X24) don't generate sound.
+		 */
+		err = snd_bebob_stream_set_rate(bebob, rate);
+		if (err < 0)
+			goto end;
+
+		err = make_both_connections(bebob, rate);
+		if (err < 0)
+			goto end;
+
+		err = start_stream(bebob, master, rate);
+		if (err < 0) {
+			dev_err(&bebob->unit->device,
+				"fail to run AMDTP master stream:%d\n", err);
+			break_both_connections(bebob);
+			goto end;
+		}
+
+		/* wait first callback */
+		if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) {
+			amdtp_stream_stop(master);
+			break_both_connections(bebob);
+			err = -ETIMEDOUT;
+			goto end;
+		}
+	}
+
+	/* start slave if needed */
+	if (slave_flag && !amdtp_stream_running(slave)) {
+		err = start_stream(bebob, slave, rate);
+		if (err < 0) {
+			dev_err(&bebob->unit->device,
+				"fail to run AMDTP slave stream:%d\n", err);
+			amdtp_stream_stop(master);
+			break_both_connections(bebob);
+			goto end;
+		}
+
+		/* wait first callback */
+		if (!amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
+			amdtp_stream_stop(slave);
+			amdtp_stream_stop(master);
+			break_both_connections(bebob);
+			err = -ETIMEDOUT;
+		}
+	}
+end:
+	mutex_unlock(&bebob->mutex);
+	return err;
+}
+
+int snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
+{
+	struct amdtp_stream *master, *slave;
+	enum cip_flags sync_mode;
+	unsigned int slave_substreams;
+	int err;
+
+	mutex_lock(&bebob->mutex);
+
+	err = get_roles(bebob, &sync_mode, &master, &slave);
+	if (err < 0)
+		goto end;
+
+	if (slave == &bebob->tx_stream)
+		slave_substreams = bebob->capture_substreams;
+	else
+		slave_substreams = bebob->playback_substreams;
+
+	if (slave_substreams > 0)
+		goto end;
+
+	amdtp_stream_stop(slave);
+
+	if ((bebob->capture_substreams > 0) || (bebob->playback_substreams > 0))
+		goto end;
+
+	amdtp_stream_stop(master);
+	break_both_connections(bebob);
+end:
+	mutex_unlock(&bebob->mutex);
+	return err;
+}
+
+void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
+{
+	/* vs. XRUN recovery due to discontinuity at bus reset */
+	mutex_lock(&bebob->mutex);
+
+	if ((cmp_connection_update(&bebob->in_conn) < 0) ||
+	    (cmp_connection_update(&bebob->out_conn) < 0)) {
+		amdtp_stream_pcm_abort(&bebob->rx_stream);
+		amdtp_stream_pcm_abort(&bebob->tx_stream);
+		amdtp_stream_stop(&bebob->rx_stream);
+		amdtp_stream_stop(&bebob->tx_stream);
+		/* disconnections should be done by PCM/MIDI functionalities */
+	} else {
+		amdtp_stream_update(&bebob->rx_stream);
+		amdtp_stream_update(&bebob->tx_stream);
+	}
+
+	mutex_unlock(&bebob->mutex);
+}
+
+void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
+{
+	mutex_lock(&bebob->mutex);
+
+	amdtp_stream_pcm_abort(&bebob->rx_stream);
+	amdtp_stream_pcm_abort(&bebob->tx_stream);
+
+	amdtp_stream_stop(&bebob->rx_stream);
+	amdtp_stream_stop(&bebob->tx_stream);
+	destroy_both_connections(bebob);
+
+	mutex_unlock(&bebob->mutex);
+}
+
+/*
+ * See: Table 50: Extended Stream Format Info ‘Format Hierarchy Level 2’
+ * in Additional AVC commands (Nov 2003, BridgeCo)
+ */
+static int
+parse_stream_formation(u8 *buf, unsigned int len,
+		       struct snd_bebob_stream_formation *formation)
+{
+	unsigned int i, e, channels, format;
+
+	/*
+	 * this module can support a hierarchy combination that:
+	 *  Root:	Audio and Music (0x90)
+	 *  Level 1:	AM824 Compound  (0x40)
+	 */
+	if ((buf[0] != 0x90) || (buf[1] != 0x40))
+		return -ENOSYS;
+
+	/* check sampling rate */
+	for (i = 0; i < sizeof(bridgeco_freq_table); i++) {
+		if (buf[2] == bridgeco_freq_table[i])
+			break;
+	}
+	if (i == sizeof(bridgeco_freq_table))
+		return -ENOSYS;
+
+	for (e = 0; e < buf[4]; e++) {
+		channels = buf[5 + e * 2];
+		format = buf[6 + e * 2];
+
+		switch (format) {
+		/* PCM for IEC 60958-3 */
+		case 0x00:
+		/* PCM for Multi bit linear audio (raw) */
+		case 0x06:
+			formation[i].pcm += channels;
+			break;
+		/* MIDI comformant (MMA/AMEI RP-027) */
+		case 0x0d:
+			formation[i].midi += channels;
+			break;
+		/* PCM for Multi bit linear audio (DVD-audio) */
+		case 0x07:
+		/* IEC 61937-3 to 7 */
+		case 0x01:
+		case 0x02:
+		case 0x03:
+		case 0x04:
+		case 0x05:
+		/* One Bit Audio */
+		case 0x08:	/* (Plain) Raw */
+		case 0x09:	/* (Plain) SACD */
+		case 0x0a:	/* (Encoded) Raw */
+		case 0x0b:	/* (ENcoded) SACD */
+		/* High precision Multi-bit Linear Audio */
+		case 0x0c:
+		/* Synchronization Stream (Stereo Raw audio) */
+		case 0x40:
+		/* Don't care */
+		case 0xff:
+		default:
+			return -ENOSYS;	/* not supported */
+		}
+	}
+
+	return 0;
+}
+
+static int
+fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir,
+		       unsigned short pid)
+{
+	u8 *buf;
+	struct snd_bebob_stream_formation *formations;
+	unsigned int len, eid;
+	u8 addr[AVC_BRIDGECO_ADDR_BYTES];
+	int err;
+
+	buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	if (dir == AVC_BRIDGECO_PLUG_DIR_IN)
+		formations = bebob->rx_stream_formations;
+	else
+		formations = bebob->tx_stream_formations;
+
+	for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) {
+		len = FORMAT_MAXIMUM_LENGTH;
+
+		memset(buf, 0, len);
+		avc_bridgeco_fill_unit_addr(addr, dir,
+					    AVC_BRIDGECO_PLUG_UNIT_ISOC, pid);
+		err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr,
+						     eid, buf, &len);
+		if (err < 0)
+			goto end;
+		else if (len < 3)
+			break;
+
+		/* parse and set stream formation */
+		err = parse_stream_formation(buf, len, formations);
+		if (err < 0)
+			goto end;
+	}
+end:
+	kfree(buf);
+	return err;
+}
+
+static int
+seek_msu_sync_input_plug(struct snd_bebob *bebob)
+{
+	u8 plugs[AVC_PLUG_INFO_BUF_COUNT], addr[AVC_BRIDGECO_ADDR_BYTES];
+	unsigned int i, type;
+	int err;
+
+	/* get information about Music Sub Unit */
+	err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs);
+	if (err < 0)
+		goto end;
+
+	/* seek destination plugs for 'MSU sync input' */
+	bebob->sync_input_plug = -1;
+	for (i = 0; i < plugs[0]; i++) {
+		avc_bridgeco_fill_subunit_addr(addr, 0x60,
+					       AVC_BRIDGECO_PLUG_DIR_IN, i);
+		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
+		if (err < 0)
+			goto end;
+
+		if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC)
+			bebob->sync_input_plug = i;
+	}
+end:
+	return err;
+}
+
+/* In this function, 2 means input and output */
+int snd_bebob_stream_discover(struct snd_bebob *bebob)
+{
+	u8 plugs[AVC_PLUG_INFO_BUF_COUNT], addr[AVC_BRIDGECO_ADDR_BYTES];
+	enum avc_bridgeco_plug_type type;
+	unsigned int i;
+	int err;
+
+	/* the number of plugs for isoc in/out, ext in/out  */
+	err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs);
+	if (err < 0)
+		goto end;
+
+	/*
+	 * This module supports one ISOC input plug and one ISOC output plug
+	 * then ignores the others.
+	 */
+	if (plugs[0] == 0) {
+		err = -EIO;
+		goto end;
+	}
+	avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
+				    AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
+	err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
+	if (err < 0)
+		goto end;
+	else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
+		err = -EIO;
+		goto end;
+	}
+
+	if (plugs[1] == 0) {
+		err = -EIO;
+		goto end;
+	}
+	avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
+				    AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
+	err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
+	if (err < 0)
+		goto end;
+	else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
+		err = -EIO;
+		goto end;
+	}
+
+	/* store formations */
+	for (i = 0; i < 2; i++) {
+		err = fill_stream_formations(bebob, i, 0);
+		if (err < 0)
+			goto end;
+	}
+
+	/* count external input plugs for MIDI */
+	bebob->midi_input_ports = 0;
+	for (i = 0; i < plugs[2]; i++) {
+		avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
+					    AVC_BRIDGECO_PLUG_UNIT_EXT, i);
+		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
+		if (err < 0)
+			goto end;
+		else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI)
+			bebob->midi_input_ports++;
+	}
+
+	/* count external output plugs for MIDI */
+	bebob->midi_output_ports = 0;
+	for (i = 0; i < plugs[3]; i++) {
+		avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
+					    AVC_BRIDGECO_PLUG_UNIT_EXT, i);
+		err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
+		if (err < 0)
+			goto end;
+		else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI)
+			bebob->midi_output_ports++;
+	}
+
+	/* for check source of clock later */
+	err = seek_msu_sync_input_plug(bebob);
+end:
+	return err;
+}
-- 
1.8.3.2


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/13534_NeoTech
_______________________________________________
mailing list linux1394-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux1394-devel

  parent reply	other threads:[~2014-03-21 11:10 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-21 11:09 [PATCH 00/44 v3] Enhancement of support for Firewire devices Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 01/44] firewire-lib: Add macros instead of fixed value for AMDTP Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 02/44] firewire-lib: Add 'direction' member to 'amdtp_stream' structure Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 03/44] firewire-lib: Split some codes into functions to reuse for both streams Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 04/44] firewire-lib: Add support for AMDTP in-stream and PCM capture Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 05/44] firewire-lib: Add support for MIDI capture/playback Takashi Sakamoto
2014-04-02 19:29   ` Clemens Ladisch
2014-04-02 19:42     ` [FFADO-devel] " Adrian Knoth
2014-04-02 19:58       ` Clemens Ladisch
2014-04-02 20:37         ` [FFADO-devel] [alsa-devel] " Jano Svitok
2014-04-03  8:33     ` Takashi Sakamoto
2014-04-03  8:54       ` Clemens Ladisch
2014-04-03 10:08         ` Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 06/44] firewire-lib: Give syt value as parameter to handle_out_packet() Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 07/44] firewire-lib: Add support for duplex streams synchronization in blocking mode Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 08/44] firewire-lib: Add support for channel mapping Takashi Sakamoto
2014-04-02 20:18   ` Clemens Ladisch
2014-04-03  8:37     ` Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 09/44] firewire-lib: Restrict calling flush_context_completion() when context exists Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 10/44] firewire-lib: Rename macros, variables and functions for CMP Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 11/44] firewire-lib: Add 'direction' member to 'cmp_connection' structure Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 12/44] firewire-lib: Add handling output connection by CMP Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 13/44] firewire-lib: Add a new function to check others' connection Takashi Sakamoto
2014-03-21 11:09 ` [PATCH 14/44] firewire-lib: Add support for deferred transaction Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 15/44] firewire-lib: Add some AV/C general commands Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 16/44] fireworks: Add skelton for Fireworks based devices Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 17/44] fireworks: Add transaction and some commands Takashi Sakamoto
2014-04-03 20:15   ` Clemens Ladisch
2014-04-04  4:08     ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 18/44] fireworks: Add connection and stream management Takashi Sakamoto
2014-04-03 20:56   ` Clemens Ladisch
2014-04-04 14:22     ` Takashi Sakamoto
2014-04-04 15:05       ` [alsa-devel] " Clemens Ladisch
2014-04-06 13:20         ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 19/44] fireworks/firewire-lib: Add a quirk for empty packet with TAG0 Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 20/44] fireworks/firewire-lib: Add a quirk for the meaning of dbc Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 21/44] fireworks/firewire-lib: Add a quirk for wrong dbs in tx packets Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 22/44] fireworks/firewire-libs: Add a quirk for fixed interval of reported dbc Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 23/44] fireworks: Add proc interface for debugging purpose Takashi Sakamoto
2014-04-03 21:16   ` [alsa-devel] " Clemens Ladisch
2014-04-04 11:16     ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 24/44] fireworks: Add MIDI interface Takashi Sakamoto
2014-04-03 21:20   ` [alsa-devel] " Clemens Ladisch
2014-04-06 12:03     ` Takashi Sakamoto
2014-04-06 14:52       ` Clemens Ladisch
2014-04-07 12:59         ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 25/44] fireworks/firewire-lib: Add a quirk for data blocks for MIDI in out-stream Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 26/44] fireworks: Add PCM interface Takashi Sakamoto
2014-04-04  8:48   ` Clemens Ladisch
2014-04-06 12:44     ` Takashi Sakamoto
2014-04-06 14:52       ` [alsa-devel] " Clemens Ladisch
2014-04-07  7:20         ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 27/44] fireworks: Add hwdep interface Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 28/44] fireworks: Add command/response functionality into " Takashi Sakamoto
2014-04-04  9:31   ` Clemens Ladisch
2014-04-04 11:11     ` Takashi Sakamoto
2014-04-04 12:15       ` [alsa-devel] " Clemens Ladisch
2014-04-08  2:45         ` Takashi Sakamoto
2014-04-04 15:13   ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 29/44] bebob: Add skelton for BeBoB based devices Takashi Sakamoto
2014-03-21 11:10 ` Takashi Sakamoto [this message]
2014-03-21 11:10 ` [PATCH 31/44] bebob/firewire-lib: Add a quirk for discontinuity at bus reset Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 32/44] bebob: Add proc interface for debugging purpose Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 33/44] bebob: Add MIDI interface Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 34/44] bebob: Add PCM interface Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 35/44] bebob: Add hwdep interface Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 36/44] bebob: Prepare for device specific operations Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 37/44] bebob: Add support for Terratec PHASE, EWS series and Aureon Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 38/44] bebob: Add support for Yamaha GO series Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 39/44] bebob: Add support for Focusrite Saffire/SaffirePro series Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 40/44] bebob: Add support for M-Audio usual Firewire series Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 41/44] bebob: Add support for M-Audio special " Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 42/44] bebob/firewire-lib: Add a quirk of wrong dbc in empty packet " Takashi Sakamoto
2014-03-23  2:16   ` Takashi Sakamoto
2014-03-24  1:41     ` [FFADO-devel] " Euan de Kock
2014-03-24  2:52       ` Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 43/44] bebob: Send a cue to load firmware for M-Audio " Takashi Sakamoto
2014-03-21 11:10 ` [PATCH 44/44] firewire/bebob: Add a workaround for M-Audio special " Takashi Sakamoto
2014-04-02 11:15 ` [PATCH 00/44 v3] Enhancement of support for Firewire devices Takashi Sakamoto
2014-04-03 19:17 ` David Henningsson
2014-04-04  7:04   ` Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1395400229-22957-31-git-send-email-o-takashi@sakamocchi.jp \
    --to=o-takashi@sakamocchi.jp \
    --cc=alsa-devel@alsa-project.org \
    --cc=clemens@ladisch.de \
    --cc=ffado-devel@lists.sf.net \
    --cc=linux1394-devel@lists.sourceforge.net \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.