aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrej Krutak <dev@andree.sk>2016-09-18 14:59:32 -0400
committerTakashi Iwai <tiwai@suse.de>2016-09-19 17:03:47 -0400
commita16039cbf1a1ee7e76d7d100f9e613998919ab91 (patch)
treea12d4bd94723c8ea609b71973bc3aa499322bbb6
parentcfa769695d2bc50b729db6a5973398b24d126c79 (diff)
ALSA: line6: Add hwdep interface to access the POD control messages
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> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--include/uapi/sound/asound.h3
-rw-r--r--sound/usb/line6/driver.c152
-rw-r--r--sound/usb/line6/driver.h23
3 files changed, 171 insertions, 7 deletions
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 609cadb8739d..be353a78c303 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -106,9 +106,10 @@ enum {
106 SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */ 106 SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */
107 SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ 107 SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */
108 SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ 108 SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */
109 SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */
109 110
110 /* Don't forget to change the following: */ 111 /* Don't forget to change the following: */
111 SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_TASCAM 112 SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LINE6
112}; 113};
113 114
114struct snd_hwdep_info { 115struct snd_hwdep_info {
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 8a71d45ce945..f9224ec141c8 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -17,6 +17,7 @@
17 17
18#include <sound/core.h> 18#include <sound/core.h>
19#include <sound/initval.h> 19#include <sound/initval.h>
20#include <sound/hwdep.h>
20 21
21#include "capture.h" 22#include "capture.h"
22#include "driver.h" 23#include "driver.h"
@@ -303,7 +304,7 @@ static void line6_data_received(struct urb *urb)
303 for (;;) { 304 for (;;) {
304 done = 305 done =
305 line6_midibuf_read(mb, line6->buffer_message, 306 line6_midibuf_read(mb, line6->buffer_message,
306 LINE6_MESSAGE_MAXLEN); 307 LINE6_MIDI_MESSAGE_MAXLEN);
307 308
308 if (done == 0) 309 if (done == 0)
309 break; 310 break;
@@ -315,8 +316,11 @@ static void line6_data_received(struct urb *urb)
315 line6->process_message(line6); 316 line6->process_message(line6);
316 } 317 }
317 } else { 318 } else {
319 line6->buffer_message = urb->transfer_buffer;
320 line6->message_length = urb->actual_length;
318 if (line6->process_message) 321 if (line6->process_message)
319 line6->process_message(line6); 322 line6->process_message(line6);
323 line6->buffer_message = NULL;
320 } 324 }
321 325
322 line6_start_listen(line6); 326 line6_start_listen(line6);
@@ -473,14 +477,17 @@ static void line6_destruct(struct snd_card *card)
473 struct usb_line6 *line6 = card->private_data; 477 struct usb_line6 *line6 = card->private_data;
474 struct usb_device *usbdev = line6->usbdev; 478 struct usb_device *usbdev = line6->usbdev;
475 479
476 /* free buffer memory first: */ 480 /* Free buffer memory first. We cannot depend on the existence of private
477 if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) 481 * data from the (podhd) module, it may be gone already during this call
482 */
483 if (line6->buffer_message)
478 kfree(line6->buffer_message); 484 kfree(line6->buffer_message);
479 485
480 kfree(line6->buffer_listen); 486 kfree(line6->buffer_listen);
481 487
482 /* then free URBs: */ 488 /* then free URBs: */
483 usb_free_urb(line6->urb_listen); 489 usb_free_urb(line6->urb_listen);
490 line6->urb_listen = NULL;
484 491
485 /* decrement reference counters: */ 492 /* decrement reference counters: */
486 usb_put_dev(usbdev); 493 usb_put_dev(usbdev);
@@ -522,6 +529,138 @@ static void line6_get_interval(struct usb_line6 *line6)
522 } 529 }
523} 530}
524 531
532
533/* Enable buffering of incoming messages, flush the buffer */
534static int line6_hwdep_open(struct snd_hwdep *hw, struct file *file)
535{
536 struct usb_line6 *line6 = hw->private_data;
537
538 /* NOTE: hwdep layer provides atomicity here */
539
540 line6->messages.active = 1;
541
542 return 0;
543}
544
545/* Stop buffering */
546static int line6_hwdep_release(struct snd_hwdep *hw, struct file *file)
547{
548 struct usb_line6 *line6 = hw->private_data;
549
550 line6->messages.active = 0;
551
552 return 0;
553}
554
555/* Read from circular buffer, return to user */
556static long
557line6_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
558 loff_t *offset)
559{
560 struct usb_line6 *line6 = hwdep->private_data;
561 long rv = 0;
562 unsigned int out_count;
563
564 if (mutex_lock_interruptible(&line6->messages.read_lock))
565 return -ERESTARTSYS;
566
567 while (kfifo_len(&line6->messages.fifo) == 0) {
568 mutex_unlock(&line6->messages.read_lock);
569
570 rv = wait_event_interruptible(
571 line6->messages.wait_queue,
572 kfifo_len(&line6->messages.fifo) != 0);
573 if (rv < 0)
574 return rv;
575
576 if (mutex_lock_interruptible(&line6->messages.read_lock))
577 return -ERESTARTSYS;
578 }
579
580 if (kfifo_peek_len(&line6->messages.fifo) > count) {
581 /* Buffer too small; allow re-read of the current item... */
582 rv = -EINVAL;
583 } else {
584 rv = kfifo_to_user(&line6->messages.fifo, buf, count, &out_count);
585 if (rv == 0)
586 rv = out_count;
587 }
588
589 mutex_unlock(&line6->messages.read_lock);
590 return rv;
591}
592
593/* Write directly (no buffering) to device by user*/
594static long
595line6_hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count,
596 loff_t *offset)
597{
598 struct usb_line6 *line6 = hwdep->private_data;
599 int rv;
600 char *data_copy;
601
602 if (count > line6->max_packet_size * LINE6_RAW_MESSAGES_MAXCOUNT) {
603 /* This is an arbitrary limit - still better than nothing... */
604 return -EINVAL;
605 }
606
607 data_copy = memdup_user(data, count);
608 if (IS_ERR(ERR_PTR))
609 return -ENOMEM;
610
611 rv = line6_send_raw_message(line6, data_copy, count);
612
613 kfree(data_copy);
614 return rv;
615}
616
617static const struct snd_hwdep_ops hwdep_ops = {
618 .open = line6_hwdep_open,
619 .release = line6_hwdep_release,
620 .read = line6_hwdep_read,
621 .write = line6_hwdep_write,
622};
623
624/* Insert into circular buffer */
625static void line6_hwdep_push_message(struct usb_line6 *line6)
626{
627 if (!line6->messages.active)
628 return;
629
630 if (kfifo_avail(&line6->messages.fifo) >= line6->message_length) {
631 /* No race condition here, there's only one writer */
632 kfifo_in(&line6->messages.fifo,
633 line6->buffer_message, line6->message_length);
634 } /* else TODO: signal overflow */
635
636 wake_up_interruptible(&line6->messages.wait_queue);
637}
638
639static int line6_hwdep_init(struct usb_line6 *line6)
640{
641 int err;
642 struct snd_hwdep *hwdep;
643
644 /* TODO: usb_driver_claim_interface(); */
645 line6->process_message = line6_hwdep_push_message;
646 line6->messages.active = 0;
647 init_waitqueue_head(&line6->messages.wait_queue);
648 mutex_init(&line6->messages.read_lock);
649 INIT_KFIFO(line6->messages.fifo);
650
651 err = snd_hwdep_new(line6->card, "config", 0, &hwdep);
652 if (err < 0)
653 goto end;
654 strcpy(hwdep->name, "config");
655 hwdep->iface = SNDRV_HWDEP_IFACE_LINE6;
656 hwdep->ops = hwdep_ops;
657 hwdep->private_data = line6;
658 hwdep->exclusive = true;
659
660end:
661 return err;
662}
663
525static int line6_init_cap_control(struct usb_line6 *line6) 664static int line6_init_cap_control(struct usb_line6 *line6)
526{ 665{
527 int ret; 666 int ret;
@@ -536,9 +675,13 @@ static int line6_init_cap_control(struct usb_line6 *line6)
536 return -ENOMEM; 675 return -ENOMEM;
537 676
538 if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { 677 if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
539 line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); 678 line6->buffer_message = kmalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL);
540 if (!line6->buffer_message) 679 if (!line6->buffer_message)
541 return -ENOMEM; 680 return -ENOMEM;
681 } else {
682 ret = line6_hwdep_init(line6);
683 if (ret < 0)
684 return ret;
542 } 685 }
543 686
544 ret = line6_start_listen(line6); 687 ret = line6_start_listen(line6);
@@ -716,3 +859,4 @@ EXPORT_SYMBOL_GPL(line6_resume);
716MODULE_AUTHOR(DRIVER_AUTHOR); 859MODULE_AUTHOR(DRIVER_AUTHOR);
717MODULE_DESCRIPTION(DRIVER_DESC); 860MODULE_DESCRIPTION(DRIVER_DESC);
718MODULE_LICENSE("GPL"); 861MODULE_LICENSE("GPL");
862
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
index 88cf1e750060..7e3a3aada222 100644
--- a/sound/usb/line6/driver.h
+++ b/sound/usb/line6/driver.h
@@ -12,8 +12,9 @@
12#ifndef DRIVER_H 12#ifndef DRIVER_H
13#define DRIVER_H 13#define DRIVER_H
14 14
15#include <linux/spinlock.h>
16#include <linux/usb.h> 15#include <linux/usb.h>
16#include <linux/mutex.h>
17#include <linux/kfifo.h>
17#include <sound/core.h> 18#include <sound/core.h>
18 19
19#include "midi.h" 20#include "midi.h"
@@ -32,7 +33,16 @@
32 33
33#define LINE6_TIMEOUT 1 34#define LINE6_TIMEOUT 1
34#define LINE6_BUFSIZE_LISTEN 64 35#define LINE6_BUFSIZE_LISTEN 64
35#define LINE6_MESSAGE_MAXLEN 256 36#define LINE6_MIDI_MESSAGE_MAXLEN 256
37
38#define LINE6_RAW_MESSAGES_MAXCOUNT_ORDER 7
39/* 4k packets are common, BUFSIZE * MAXCOUNT should be bigger... */
40#define LINE6_RAW_MESSAGES_MAXCOUNT (1 << LINE6_RAW_MESSAGES_MAXCOUNT_ORDER)
41
42
43#if LINE6_BUFSIZE_LISTEN > 65535
44#error "Use dynamic fifo instead"
45#endif
36 46
37/* 47/*
38 Line 6 MIDI control commands 48 Line 6 MIDI control commands
@@ -156,6 +166,15 @@ struct usb_line6 {
156 /* Length of message to be processed, generated from MIDI layer */ 166 /* Length of message to be processed, generated from MIDI layer */
157 int message_length; 167 int message_length;
158 168
169 /* Circular buffer for non-MIDI control messages */
170 struct {
171 struct mutex read_lock;
172 wait_queue_head_t wait_queue;
173 unsigned int active:1;
174 STRUCT_KFIFO_REC_2(LINE6_BUFSIZE_LISTEN * LINE6_RAW_MESSAGES_MAXCOUNT)
175 fifo;
176 } messages;
177
159 /* If MIDI is supported, buffer_message contains the pre-processed data; 178 /* If MIDI is supported, buffer_message contains the pre-processed data;
160 * otherwise the data is only in urb_listen (buffer_incoming). 179 * otherwise the data is only in urb_listen (buffer_incoming).
161 */ 180 */