All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrej Krutak <dev@andree.sk>
To: tiwai@suse.com, perex@perex.cz, stefanha@gmail.com,
	grabner@icg.tugraz.at, alsa-devel@alsa-project.org
Cc: Andrej Krutak <dev@andree.sk>
Subject: [PATCH v4 12/12] ALSA: line6: Add hwdep interface to access the POD control messages
Date: Sun, 18 Sep 2016 20:59:32 +0200	[thread overview]
Message-ID: <1474225172-32081-13-git-send-email-dev@andree.sk> (raw)
In-Reply-To: <1474225172-32081-1-git-send-email-dev@andree.sk>

We must do it this way, because e.g. POD X3 won't play any sound unless
the host listens on the bulk EP, so we cannot export it only via libusb.

The driver currently doesn't use the bulk EP messages in other way,
in future it could e.g. sense/modify volume(s).

Signed-off-by: Andrej Krutak <dev@andree.sk>
---
 include/uapi/sound/asound.h |   3 +-
 sound/usb/line6/driver.c    | 151 ++++++++++++++++++++++++++++++++++++++++++--
 sound/usb/line6/driver.h    |  23 ++++++-
 3 files changed, 170 insertions(+), 7 deletions(-)

diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 609cadb..be353a7 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -106,9 +106,10 @@ enum {
 	SNDRV_HWDEP_IFACE_FW_OXFW,	/* Oxford OXFW970/971 based device */
 	SNDRV_HWDEP_IFACE_FW_DIGI00X,	/* Digidesign Digi 002/003 family */
 	SNDRV_HWDEP_IFACE_FW_TASCAM,	/* TASCAM FireWire series */
+	SNDRV_HWDEP_IFACE_LINE6,	/* Line6 USB processors */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_TASCAM
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LINE6
 };
 
 struct snd_hwdep_info {
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 8a71d45..3536efe 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -17,6 +17,7 @@
 
 #include <sound/core.h>
 #include <sound/initval.h>
+#include <sound/hwdep.h>
 
 #include "capture.h"
 #include "driver.h"
@@ -303,7 +304,7 @@ static void line6_data_received(struct urb *urb)
 		for (;;) {
 			done =
 				line6_midibuf_read(mb, line6->buffer_message,
-						LINE6_MESSAGE_MAXLEN);
+						LINE6_MIDI_MESSAGE_MAXLEN);
 
 			if (done == 0)
 				break;
@@ -315,8 +316,11 @@ static void line6_data_received(struct urb *urb)
 				line6->process_message(line6);
 		}
 	} else {
+		line6->buffer_message = urb->transfer_buffer;
+		line6->message_length = urb->actual_length;
 		if (line6->process_message)
 			line6->process_message(line6);
+		line6->buffer_message = NULL;
 	}
 
 	line6_start_listen(line6);
@@ -473,14 +477,16 @@ static void line6_destruct(struct snd_card *card)
 	struct usb_line6 *line6 = card->private_data;
 	struct usb_device *usbdev = line6->usbdev;
 
-	/* free buffer memory first: */
-	if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI)
+	/* Free buffer memory first. We cannot depend on the existence of private
+	 * data from the (podhd) module, it may be gone already during this call */
+	if (line6->buffer_message)
 		kfree(line6->buffer_message);
 
 	kfree(line6->buffer_listen);
 
 	/* then free URBs: */
 	usb_free_urb(line6->urb_listen);
+	line6->urb_listen = NULL;
 
 	/* decrement reference counters: */
 	usb_put_dev(usbdev);
@@ -522,6 +528,138 @@ static void line6_get_interval(struct usb_line6 *line6)
 	}
 }
 
+
+/* Enable buffering of incoming messages, flush the buffer */
+static int line6_hwdep_open(struct snd_hwdep *hw, struct file *file)
+{
+	struct usb_line6 *line6 = hw->private_data;
+
+	/* NOTE: hwdep layer provides atomicity here */
+
+	line6->messages.active = 1;
+
+	return 0;
+}
+
+/* Stop buffering */
+static int line6_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+	struct usb_line6 *line6 = hw->private_data;
+
+	line6->messages.active = 0;
+
+	return 0;
+}
+
+/* Read from circular buffer, return to user */
+static long
+line6_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
+					loff_t *offset)
+{
+	struct usb_line6 *line6 = hwdep->private_data;
+	long rv = 0;
+	unsigned int out_count;
+
+	if (mutex_lock_interruptible(&line6->messages.read_lock))
+		return -ERESTARTSYS;
+
+	while (kfifo_len(&line6->messages.fifo) == 0) {
+		mutex_unlock(&line6->messages.read_lock);
+
+		rv = wait_event_interruptible(
+			line6->messages.wait_queue,
+			kfifo_len(&line6->messages.fifo) != 0);
+		if (rv < 0)
+			return rv;
+
+		if (mutex_lock_interruptible(&line6->messages.read_lock))
+			return -ERESTARTSYS;
+	}
+
+	if (kfifo_peek_len(&line6->messages.fifo) > count) {
+		/* Buffer too small; allow re-read of the current item... */
+		rv = -EINVAL;
+	} else {
+		rv = kfifo_to_user(&line6->messages.fifo, buf, count, &out_count);
+		if (rv == 0)
+			rv = out_count;
+	}
+
+	mutex_unlock(&line6->messages.read_lock);
+	return rv;
+}
+
+/* Write directly (no buffering) to device by user*/
+static long
+line6_hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count,
+					loff_t *offset)
+{
+	struct usb_line6 *line6 = hwdep->private_data;
+	int rv;
+	char *data_copy;
+
+	if (count > line6->max_packet_size * LINE6_RAW_MESSAGES_MAXCOUNT) {
+		/* This is an arbitrary limit - still better than nothing... */
+		return -EINVAL;
+	}
+
+	data_copy = memdup_user(data, count);
+	if (IS_ERR(ERR_PTR))
+		return -ENOMEM;
+
+	rv = line6_send_raw_message(line6, data_copy, count);
+
+	kfree(data_copy);
+	return rv;
+}
+
+static const struct snd_hwdep_ops hwdep_ops = {
+	.open    = line6_hwdep_open,
+	.release = line6_hwdep_release,
+	.read    = line6_hwdep_read,
+	.write   = line6_hwdep_write,
+};
+
+/* Insert into circular buffer */
+static void line6_hwdep_push_message(struct usb_line6 *line6)
+{
+	if (!line6->messages.active)
+		return;
+
+	if (kfifo_avail(&line6->messages.fifo) >= line6->message_length) {
+		/* No race condition here, there's only one writer */
+		kfifo_in(&line6->messages.fifo,
+			line6->buffer_message, line6->message_length);
+	} /* else TODO: signal overflow */
+
+	wake_up_interruptible(&line6->messages.wait_queue);
+}
+
+static int line6_hwdep_init(struct usb_line6 *line6)
+{
+	int err;
+	struct snd_hwdep *hwdep;
+
+	/* TODO: usb_driver_claim_interface(); */
+	line6->process_message = line6_hwdep_push_message;
+	line6->messages.active = 0;
+	init_waitqueue_head(&line6->messages.wait_queue);
+	mutex_init(&line6->messages.read_lock);
+	INIT_KFIFO(line6->messages.fifo);
+
+	err = snd_hwdep_new(line6->card, "config", 0, &hwdep);
+	if (err < 0)
+		goto end;
+	strcpy(hwdep->name, "config");
+	hwdep->iface = SNDRV_HWDEP_IFACE_LINE6;
+	hwdep->ops = hwdep_ops;
+	hwdep->private_data = line6;
+	hwdep->exclusive = true;
+
+end:
+	return err;
+}
+
 static int line6_init_cap_control(struct usb_line6 *line6)
 {
 	int ret;
@@ -536,9 +674,13 @@ static int line6_init_cap_control(struct usb_line6 *line6)
 		return -ENOMEM;
 
 	if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
-		line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+		line6->buffer_message = kmalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL);
 		if (!line6->buffer_message)
 			return -ENOMEM;
+	} else {
+		ret = line6_hwdep_init(line6);
+		if (ret < 0)
+			return ret;
 	}
 
 	ret = line6_start_listen(line6);
@@ -716,3 +858,4 @@ EXPORT_SYMBOL_GPL(line6_resume);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
index d7eefe1..cf9f077 100644
--- a/sound/usb/line6/driver.h
+++ b/sound/usb/line6/driver.h
@@ -12,8 +12,9 @@
 #ifndef DRIVER_H
 #define DRIVER_H
 
-#include <linux/spinlock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/kfifo.h>
 #include <sound/core.h>
 
 #include "midi.h"
@@ -32,7 +33,16 @@
 
 #define LINE6_TIMEOUT 1
 #define LINE6_BUFSIZE_LISTEN 64
-#define LINE6_MESSAGE_MAXLEN 256
+#define LINE6_MIDI_MESSAGE_MAXLEN 256
+
+#define LINE6_RAW_MESSAGES_MAXCOUNT_ORDER 7
+/* 4k packets are common, BUFSIZE * MAXCOUNT should be bigger... */
+#define LINE6_RAW_MESSAGES_MAXCOUNT (1 << LINE6_RAW_MESSAGES_MAXCOUNT_ORDER)
+
+
+#if LINE6_BUFSIZE_LISTEN > 65535
+#error "Use dynamic fifo instead"
+#endif
 
 /*
 	Line 6 MIDI control commands
@@ -156,6 +166,15 @@ struct usb_line6 {
 	/* Length of message to be processed, generated from MIDI layer  */
 	int message_length;
 
+	/* Circular buffer for non-MIDI control messages */
+	struct {
+		struct mutex read_lock;
+		wait_queue_head_t wait_queue;
+		int active:1;
+		STRUCT_KFIFO_REC_2(LINE6_BUFSIZE_LISTEN * LINE6_RAW_MESSAGES_MAXCOUNT)
+			fifo;
+	} messages;
+
 	/* If MIDI is supported, buffer_message contains the pre-processed data;
 	 * otherwise the data is only in urb_listen (buffer_incoming). */
 	void (*process_message)(struct usb_line6 *);
-- 
1.9.1

  parent reply	other threads:[~2016-09-18 19:01 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-11 19:02 [PATCH 00/15] Line6 POD X3/X3Live suport Andrej Krutak
2016-08-11 19:02 ` [PATCH 01/15] ALSA: line6: Make driver configuration more generic Andrej Krutak
2016-08-12  8:24   ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 02/15] ALSA: line6: Add LINE6_CAP_IN_NEEDS_OUT, a void playback stream during capture Andrej Krutak
2016-08-11 19:02 ` [PATCH 03/15] ALSA: line6: Distinguish device init (ctrl EP) and MIDI data transfer (int EP) Andrej Krutak
2016-08-11 19:02 ` [PATCH 04/15] ALSA: line6: Add support for POD X3 Andrej Krutak
2016-08-11 19:02 ` [PATCH 05/15] ALSA: line6: Use device_create_file instead of snd_card_add_dev_attr Andrej Krutak
2016-08-12  8:26   ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 06/15] ALSA: line6: Allow bulk endpoints instead of interrupt endpoints Andrej Krutak
2016-08-11 19:02 ` [PATCH 07/15] ALSA: line6: Allow processing of raw incoming messages Andrej Krutak
2016-08-11 19:02 ` [PATCH 08/15] ALSA: line6: Cleanup initialization Andrej Krutak
2016-08-11 19:02 ` [PATCH 09/15] ALSA: line6: Add hwdep interface to access the POD control messages Andrej Krutak
2016-08-12  8:44   ` Takashi Iwai
2016-08-12 11:10     ` Andrej Kruták
2016-08-12 12:03       ` Takashi Iwai
2016-08-12 12:15         ` Andrej Kruták
2016-08-12 12:30           ` Takashi Iwai
2016-08-12 16:43             ` Andrej Kruták
2016-08-12 20:01               ` Takashi Iwai
2016-08-14  7:59                 ` Andrej Kruták
2016-08-11 19:02 ` [PATCH 10/15] ALSA: line6: Add proper locks for hwdep open/release/read Andrej Krutak
2016-08-12  8:44   ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 11/15] ALSA: line6: Only free buffer if it is set Andrej Krutak
2016-08-12  8:45   ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 12/15] ALSA: line6: Give up on the lock while URBs are released Andrej Krutak
2016-08-12  8:45   ` Takashi Iwai
2016-08-12 11:14     ` Andrej Kruták
2016-08-12 12:04       ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 13/15] ALSA: line6: Add support for POD X3 Live (only USB ID differs from POD X3) Andrej Krutak
2016-08-11 19:02 ` [PATCH 14/15] ALSA: line6: Give up hwdep spinlock temporarily during read operation Andrej Krutak
2016-08-12  8:46   ` Takashi Iwai
2016-08-11 19:02 ` [PATCH 15/15] ALSA: line6: Remove double line6_pcm_release() after failed acquire Andrej Krutak
2016-08-12  8:46   ` Takashi Iwai
2016-08-12  8:14 ` [PATCH 00/15] Line6 POD X3/X3Live suport Takashi Iwai
2016-08-12 10:31   ` Andrej Kruták
2016-08-18 22:20 ` [PATCH v2 0/9] " Andrej Krutak
2016-08-18 22:20   ` [PATCH v2 1/9] ALSA: line6: Make driver configuration more generic Andrej Krutak
2016-08-24 14:50     ` Takashi Iwai
2016-08-18 22:20   ` [PATCH v2 2/9] ALSA: line6: Add LINE6_CAP_IN_NEEDS_OUT, a void playback stream during capture Andrej Krutak
2016-08-24 14:53     ` Takashi Iwai
2016-08-18 22:20   ` [PATCH v2 3/9] ALSA: line6: Distinguish device init (ctrl EP) and MIDI data transfer (int EP) Andrej Krutak
2016-08-24 14:56     ` Takashi Iwai
2016-08-18 22:20   ` [PATCH v2 4/9] ALSA: line6: Add support for POD X3 Andrej Krutak
2016-08-18 22:20   ` [PATCH v2 5/9] ALSA: line6: Add support for POD X3 Live (only USB ID differs from POD X3) Andrej Krutak
2016-08-18 22:20   ` [PATCH v2 6/9] ALSA: line6: Allow bulk endpoints instead of interrupt endpoints Andrej Krutak
2016-08-24 15:02     ` Takashi Iwai
2016-08-18 22:20   ` [PATCH v2 7/9] ALSA: line6: Allow processing of raw incoming messages Andrej Krutak
2016-08-24 15:05     ` Takashi Iwai
2016-08-30 14:35       ` Andrej Kruták
2016-08-18 22:20   ` [PATCH v2 8/9] ALSA: line6: Cleanup initialization Andrej Krutak
2016-08-24 15:06     ` Takashi Iwai
2016-08-18 22:20   ` [PATCH v2 9/9] ALSA: line6: Add hwdep interface to access the POD control messages Andrej Krutak
2016-09-16  9:12 ` [PATCH v3 00/12] Line6 POD X3/X3Live suport Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 01/12] ALSA: line6: Enable different number of URBs for frame transfers Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 02/12] ALSA: line6: Add high-speed USB support Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 03/12] ALSA: line6: Support assymetrical in/out configurations Andrej Krutak
2016-09-16 18:34     ` kbuild test robot
2016-09-16  9:12   ` [PATCH v3 04/12] ALSA: line6: Allow different channel numbers for in/out Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 05/12] ALSA: line6: Add LINE6_CAP_IN_NEEDS_OUT, a void playback stream during capture Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 06/12] ALSA: line6: Distinguish device init (ctrl EP) and MIDI data transfer (int EP) Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 07/12] ALSA: line6: Allow processing of raw incoming messages Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 08/12] ALSA: line6: Add support for POD X3 Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 09/12] ALSA: line6: Add support for POD X3 Live (only USB ID differs from POD X3) Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 10/12] ALSA: line6: Only determine control port properties if needed Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 11/12] ALSA: line6: Cleanup podhd initialization Andrej Krutak
2016-09-16  9:12   ` [PATCH v3 12/12] ALSA: line6: Add hwdep interface to access the POD control messages Andrej Krutak
2016-09-18 18:59 ` [PATCH v4 00/12] Line6 POD X3/X3Live suport Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 01/12] ALSA: line6: Enable different number of URBs for frame transfers Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 02/12] ALSA: line6: Add high-speed USB support Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 03/12] ALSA: line6: Support assymetrical in/out configurations Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 04/12] ALSA: line6: Allow different channel numbers for in/out Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 05/12] ALSA: line6: Add LINE6_CAP_IN_NEEDS_OUT, a void playback stream during capture Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 06/12] ALSA: line6: Distinguish device init (ctrl EP) and MIDI data transfer (int EP) Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 07/12] ALSA: line6: Allow processing of raw incoming messages Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 08/12] ALSA: line6: Add support for POD X3 Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 09/12] ALSA: line6: Add support for POD X3 Live (only USB ID differs from POD X3) Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 10/12] ALSA: line6: Only determine control port properties if needed Andrej Krutak
2016-09-18 18:59   ` [PATCH v4 11/12] ALSA: line6: Cleanup podhd initialization Andrej Krutak
2016-09-18 18:59   ` Andrej Krutak [this message]
2016-09-19 21:06     ` [PATCH v4 12/12] ALSA: line6: Add hwdep interface to access the POD control messages Takashi Iwai
2016-09-19 21:07   ` [PATCH v4 00/12] Line6 POD X3/X3Live suport 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=1474225172-32081-13-git-send-email-dev@andree.sk \
    --to=dev@andree.sk \
    --cc=alsa-devel@alsa-project.org \
    --cc=grabner@icg.tugraz.at \
    --cc=perex@perex.cz \
    --cc=stefanha@gmail.com \
    --cc=tiwai@suse.com \
    /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.