diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 460f8eb..c4990ad 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -13,6 +13,10 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
 	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 	int err;
 
+	/* This port is for Asynchronous transaction. */
+	if (substream->number == 0)
+		return 0;
+
 	err = snd_dg00x_stream_lock_try(dg00x);
 	if (err < 0)
 		return err;
@@ -32,6 +36,10 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
 	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 	int err;
 
+	/* This port is for Asynchronous transaction. */
+	if (substream->number == 0)
+		return 0;
+
 	err = snd_dg00x_stream_lock_try(dg00x);
 	if (err < 0)
 		return err;
@@ -50,6 +58,9 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
 {
 	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 
+	if (substream->number == 0)
+		return 0;
+
 	mutex_lock(&dg00x->mutex);
 	dg00x->capture_substreams--;
 	snd_dg00x_stream_stop_duplex(dg00x);
@@ -63,6 +74,9 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
 {
 	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 
+	if (substream->number == 0)
+		return 0;
+
 	mutex_lock(&dg00x->mutex);
 	dg00x->playback_substreams--;
 	snd_dg00x_stream_stop_duplex(dg00x);
@@ -79,12 +93,19 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
 
 	spin_lock_irqsave(&dg00x->lock, flags);
 
-	if (up)
-		amdtp_stream_midi_trigger(&dg00x->tx_stream,
-					  substrm->number, substrm);
-	else
-		amdtp_stream_midi_trigger(&dg00x->tx_stream,
-					  substrm->number, NULL);
+	if (substrm->number == 0) {
+		if (up)
+			dg00x->in_control = substrm;
+		else
+			dg00x->in_control = NULL;
+	} else {
+		if (up)
+			amdtp_stream_midi_trigger(&dg00x->tx_stream,
+						  substrm->number - 1, substrm);
+		else
+			amdtp_stream_midi_trigger(&dg00x->tx_stream,
+						  substrm->number - 1, NULL);
+	}
 
 	spin_unlock_irqrestore(&dg00x->lock, flags);
 }
@@ -96,12 +117,21 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
 
 	spin_lock_irqsave(&dg00x->lock, flags);
 
-	if (up)
-		amdtp_stream_midi_trigger(&dg00x->rx_stream,
-					  substrm->number, substrm);
-	else
-		amdtp_stream_midi_trigger(&dg00x->rx_stream,
-					  substrm->number, NULL);
+	if (substrm->number == 0) {
+		if (up) {
+			dg00x->out_control = substrm;
+			snd_dg00x_protocol_queue_midi_message(dg00x);
+		} else {
+			dg00x->out_control = NULL;
+		}
+	} else {
+		if (up)
+			amdtp_stream_midi_trigger(&dg00x->rx_stream,
+						  substrm->number - 1, substrm);
+		else
+			amdtp_stream_midi_trigger(&dg00x->rx_stream,
+						  substrm->number - 1, NULL);
+	}
 
 	spin_unlock_irqrestore(&dg00x->lock, flags);
 }
@@ -124,9 +154,15 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x,
 	struct snd_rawmidi_substream *subs;
 
 	list_for_each_entry(subs, &str->substreams, list) {
-		snprintf(subs->name, sizeof(subs->name),
-			 "%s MIDI %d",
-			 dg00x->card->shortname, subs->number + 1);
+		/* This port is for device control. */
+		if (subs->number == 0) {
+			snprintf(subs->name, sizeof(subs->name),
+				 "%s control", dg00x->card->shortname);
+		} else {
+			snprintf(subs->name, sizeof(subs->name),
+				 "%s MIDI %d",
+				 dg00x->card->shortname, subs->number + 1);
+		}
 	}
 }
 
@@ -137,7 +173,7 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
 	int err;
 
 	err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
-			      1, 2, &rmidi);
+			      3, 2, &rmidi);
 	if (err < 0)
 		return err;
 
diff --git a/sound/firewire/digi00x/digi00x-protocol.c b/sound/firewire/digi00x/digi00x-protocol.c
index b19708d..3e5b3bec 100644
--- a/sound/firewire/digi00x/digi00x-protocol.c
+++ b/sound/firewire/digi00x/digi00x-protocol.c
@@ -8,6 +8,43 @@
 
 #include "digi00x.h"
 
+struct workqueue_struct *midi_wq;
+
+static void send_midi_control(struct work_struct *work)
+{
+	struct snd_dg00x *dg00x =
+			container_of(work, struct snd_dg00x, midi_control);
+	struct fw_device *device = fw_parent_device(dg00x->unit);
+
+	unsigned int len;
+	__be32 buf = 0;
+	u8 *b = (u8 *)&buf;
+
+	/* Send MIDI control. */
+	if (!dg00x->out_control)
+		return;
+
+	do {
+		len = snd_rawmidi_transmit(dg00x->out_control, b + 1, 2);
+		if (len > 0) {
+			b[0] = 0x80;
+			b[3] = 0xc0 | len;
+
+			/* Don't check transaction status. */
+			fw_run_transaction(device->card,
+					   TCODE_WRITE_QUADLET_REQUEST,
+					   device->node_id, device->generation,
+					   device->max_speed,
+					   0xffffe0000400, &buf, sizeof(buf));
+		}
+	} while (len > 0);
+}
+
+void snd_dg00x_protocol_queue_midi_message(struct snd_dg00x *dg00x)
+{
+	queue_work(midi_wq, &dg00x->midi_control);
+}
+
 static struct snd_dg00x *instances[SNDRV_CARDS];
 static DEFINE_SPINLOCK(instances_lock);
 
@@ -17,6 +54,26 @@ static void handle_unknown_message(struct snd_dg00x *dg00x,
 	snd_printk(KERN_INFO"%08llx: %08x\n", offset, be32_to_cpu(*buf));
 }
 
+static void handle_midi_control(struct snd_dg00x *dg00x, u32 *buf,
+				unsigned int length)
+{
+	unsigned int i;
+	unsigned int len;
+	u8 *b;
+
+	if (dg00x->in_control == NULL)
+		return;
+
+	length /= 4;
+
+	for (i = 0; i < length; i++) {
+		b = (u8 *)&buf[i];
+		len = b[3] & 0xf;
+		if (len > 0)
+			snd_rawmidi_receive(dg00x->in_control, b + 1, len);
+	}
+}
+
 static void handle_message(struct fw_card *card, struct fw_request *request,
 			   int tcode, int destination, int source,
 			   int generation, unsigned long long offset,
@@ -43,6 +100,8 @@ static void handle_message(struct fw_card *card, struct fw_request *request,
 
 	if (offset == 0xffffe0000000)
 		handle_unknown_message(dg00x, offset, buf);
+	else if (offset == 0xffffe0000004)
+		handle_midi_control(dg00x, buf, length);
 
 	spin_unlock_irq(&instances_lock);
 	fw_send_response(card, request, RCODE_COMPLETE);
@@ -70,6 +129,15 @@ int snd_dg00x_protocol_add_instance(struct snd_dg00x *dg00x)
 	if (err < 0)
 		return err;
 
+	/* Asynchronous transactions for MIDI control message. 8 bytes. */
+	data[0] = cpu_to_be32((device->card->node_id << 16) |
+			      (async_handler.offset >> 32));
+	data[1] = cpu_to_be32(async_handler.offset + 4);
+	err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_BLOCK_REQUEST,
+				 0xffffe0000008ull, &data, sizeof(data), 0);
+	if (err < 0)
+		return err;
+
 	spin_lock_irq(&instances_lock);
 	for (i = 0; i < SNDRV_CARDS; i++) {
 		if (instances[i] != NULL)
@@ -79,6 +147,8 @@ int snd_dg00x_protocol_add_instance(struct snd_dg00x *dg00x)
 	}
 	spin_unlock_irq(&instances_lock);
 
+	INIT_WORK(&dg00x->midi_control, send_midi_control);
+
 	return 0;
 }
 
@@ -104,19 +174,27 @@ int snd_dg00x_protocol_register(void)
 	};
 	int err;
 
-	async_handler.length = 4;
+	midi_wq = alloc_workqueue("snd-digi00x",
+				  WQ_SYSFS | WQ_POWER_EFFICIENT, 0);
+	if (midi_wq == NULL)
+		return -ENOMEM;
+
+	async_handler.length = 12;
 	async_handler.address_callback = handle_message;
 	async_handler.callback_data = NULL;
 
 	err = fw_core_add_address_handler(&async_handler,
 					  &resp_register_region);
-	if (err < 0)
+	if (err < 0) {
+		destroy_workqueue(midi_wq);
 		return err;
+	}
 
 	return 0;
 }
 
 void snd_dg00x_protocol_unregister(void)
 {
+	destroy_workqueue(midi_wq);
 	fw_core_remove_address_handler(&async_handler);
 }
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 85cfb39..20b178f 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -17,6 +17,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -53,6 +54,11 @@ struct snd_dg00x {
 	int dev_lock_count;
 	bool dev_lock_changed;
 	wait_queue_head_t hwdep_wait;
+
+	/* For asynchronous MIDI controls. */
+	struct work_struct midi_control;
+	struct snd_rawmidi_substream *in_control;
+	struct snd_rawmidi_substream *out_control;
 };
 
 /* values for SND_DG00X_ADDR_OFFSET_RATE */
@@ -78,6 +84,7 @@ enum snd_dg00x_optical_mode {
 	SND_DG00X_OPTICAL_MODE_SPDIF,
 };
 
+void snd_dg00x_protocol_queue_midi_message(struct snd_dg00x *dg00x);
 int snd_dg00x_protocol_add_instance(struct snd_dg00x *dg00x);
 void snd_dg00x_protocol_remove_instance(struct snd_dg00x *dg00x);
 int snd_dg00x_protocol_register(void);
