From patchwork Fri Sep 16 09:12:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrej Krutak X-Patchwork-Id: 9335745 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0DD9D60839 for ; Fri, 16 Sep 2016 12:52:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F030629F88 for ; Fri, 16 Sep 2016 12:52:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E352929F8A; Fri, 16 Sep 2016 12:52:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_NONE,T_DKIM_INVALID autolearn=no version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7CA8D29F88 for ; Fri, 16 Sep 2016 12:52:39 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9E7E4267033; Fri, 16 Sep 2016 14:52:38 +0200 (CEST) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id D315C266829; Fri, 16 Sep 2016 14:50:09 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 0B7C22667DF; Fri, 16 Sep 2016 11:13:32 +0200 (CEST) Received: from mail-wm0-f66.google.com (mail-wm0-f66.google.com [74.125.82.66]) by alsa0.perex.cz (Postfix) with ESMTP id 87702266718 for ; Fri, 16 Sep 2016 11:13:30 +0200 (CEST) Received: by mail-wm0-f66.google.com with SMTP id b184so2695619wma.3 for ; Fri, 16 Sep 2016 02:13:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=wAUYVzPJhrP7NwdkO9eM/s22vkpLcw6drcn262tcMTM=; b=BvgDM2N0+N/W+mf3pIx50x1x8o/cIJPcpUQO9bfmUFCYSJNLB5lOz80XQV5cJLOd0j HwSr83f7thQRmMaHSOs2VwZtwmgo/xnJ+8y50kwTqObiaVt4+Ac7LtrjfCRtaMQu0FDj HTVMnPn1PlhbIOFHZHnk5k+0aCZneKEFFOTo/gUGDoAYvJZvQmVF+HYKJR0rdWgqEcYr muvWnw7hkoLEV2b3unPRS2++LNe2y/hIdAJ3/aATjU9gS0FAVUPoc/pXf75faxbIya/0 i/co4sE8ltqHxiQ88EqdNDJwANrSiQbE3N3p1iWIFQVTtPlXq5iJHn/TE3iIZRamHpMV 557Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=wAUYVzPJhrP7NwdkO9eM/s22vkpLcw6drcn262tcMTM=; b=KgzxSK8Jv5TWgmEHsa91zM5UP3IZuD3TUAI1I6gRE4apxCFuw6xD7vJRe3WnQXyMiG uRUtjq/CH3iwOT7VUqWdSmk0KC2cXPasOdcTJjefMocfu5j/RLY8dHcCZqJMwHRzMlYy kuICeecTtPrTrnxU7GZvWAf2gLM5gKjB7cMw3uTuB0RFSzcWoP5QK3eVFhov+lUS7FnJ ATD/iqPonwbhrB3Hth4cN8r5Obe4x+bF4XCEepGklI5Rd0euuK9ZqyoD4w7GV0DNeURV BoGjoPljHMuStkqXQ8bM8xiqUHsYq58Ng2BsQ/JFokWy6yRMt7uQwuHtL8WCLVcZd7ML Lusg== X-Gm-Message-State: AE9vXwMc6vHlUVkfktwSEKHZVEFxT3N+nXHDLrOxe5mMSx+yarNDzPsNOF5p0oKc85PYyg== X-Received: by 10.194.79.199 with SMTP id l7mr12540766wjx.122.1474017210033; Fri, 16 Sep 2016 02:13:30 -0700 (PDT) Received: from localhost.localdomain ([217.30.74.231]) by smtp.gmail.com with ESMTPSA id u124sm6391513wmu.10.2016.09.16.02.13.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Sep 2016 02:13:29 -0700 (PDT) From: Andrej Krutak To: tiwai@suse.com, perex@perex.cz, stefanha@gmail.com, grabner@icg.tugraz.at, alsa-devel@alsa-project.org Date: Fri, 16 Sep 2016 11:12:56 +0200 Message-Id: <1474017177-23769-13-git-send-email-dev@andree.sk> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1474017177-23769-1-git-send-email-dev@andree.sk> References: <1470942147-19848-1-git-send-email-dev@andree.sk> <1474017177-23769-1-git-send-email-dev@andree.sk> Cc: Andrej Krutak Subject: [alsa-devel] [PATCH v3 12/12] ALSA: line6: Add hwdep interface to access the POD control messages X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 #include +#include #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 #include +#include +#include #include #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 *);