ALSA: line6: Add high-speed USB support
authorAndrej Krutak <dev@andree.sk>
Sun, 18 Sep 2016 18:59:22 +0000 (20:59 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 19 Sep 2016 20:58:50 +0000 (22:58 +0200)
This has two parts:
* intervals_per_second setup
  (high speed needs 8000, instead of 1000)
* iso_buffers setup (count of iso buffers depends on
  USB speed, 2 is not enough for high speed)

Signed-off-by: Andrej Krutak <dev@andree.sk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/line6/capture.c
sound/usb/line6/driver.c
sound/usb/line6/driver.h
sound/usb/line6/pcm.h
sound/usb/line6/playback.c

index c2808a0b771a400def8ef7807abd6df040e8a6ca..596bc53d0775a81267200cd7d1421e334b7104da 100644 (file)
@@ -181,7 +181,15 @@ static void audio_in_callback(struct urb *urb)
 
                length += fsize;
 
-               /* the following assumes LINE6_ISO_PACKETS == 1: */
+               BUILD_BUG_ON_MSG(LINE6_ISO_PACKETS != 1,
+                       "The following code assumes LINE6_ISO_PACKETS == 1");
+               /* TODO:
+                * Also, if iso_buffers != 2, the prev frame is almost random at
+                * playback side.
+                * This needs to be redesigned. It should be "stable", but we may
+                * experience sync problems on such high-speed configs.
+                */
+
                line6pcm->prev_fbuf = fbuf;
                line6pcm->prev_fsize = fsize;
 
index 527c4086f6fc3d6c48d7ba47af90c8e8e9796ac0..14032d96da6749080d5bef05c27a3d9c3c26c417 100644 (file)
@@ -462,14 +462,18 @@ static void line6_destruct(struct snd_card *card)
 static void line6_get_interval(struct usb_line6 *line6)
 {
        struct usb_device *usbdev = line6->usbdev;
-       struct usb_host_endpoint *ep;
-       unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
-       unsigned epnum = usb_pipeendpoint(pipe);
+       struct usb_host_endpoint *ep = usbdev->ep_in[line6->properties->ep_ctrl_r];
 
-       ep = usbdev->ep_in[epnum];
-       line6->iso_buffers = LINE6_ISO_BUFFERS;
        if (ep) {
                line6->interval = ep->desc.bInterval;
+               if (usbdev->speed == USB_SPEED_LOW) {
+                       line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
+                       line6->iso_buffers = USB_LOW_ISO_BUFFERS;
+               } else {
+                       line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
+                       line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
+               }
+
                line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
        } else {
                dev_err(line6->ifcdev,
@@ -559,6 +563,7 @@ int line6_probe(struct usb_interface *interface,
        /* query interface number */
        interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
 
+       /* TODO reserves the bus bandwidth even without actual transfer */
        ret = usb_set_interface(usbdev, interface_number,
                                properties->altsetting);
        if (ret < 0) {
index 43dd1d06b5facfa736d20f59cfa69733fc58f902..a55eb8871b51322f12c4528de3e303f26c2a2edf 100644 (file)
 
 #include "midi.h"
 
-#define USB_INTERVALS_PER_SECOND 1000
+/* USB 1.1 speed configuration */
+#define USB_LOW_INTERVALS_PER_SECOND 1000
+#define USB_LOW_ISO_BUFFERS 2
+
+/* USB 2.0+ speed configuration */
+#define USB_HIGH_INTERVALS_PER_SECOND 8000
+#define USB_HIGH_ISO_BUFFERS 16
 
 /* Fallback USB interval and max packet size values */
 #define LINE6_FALLBACK_INTERVAL 10
@@ -109,12 +115,15 @@ struct usb_line6 {
        /* Properties */
        const struct line6_properties *properties;
 
-       /* Interval (ms) */
+       /* Interval for data USB packets */
        int interval;
+       /* ...for isochronous transfers framing */
+       int intervals_per_second;
+
        /* Number of isochronous URBs used for frame transfers */
        int iso_buffers;
 
-       /* Maximum size of USB packet */
+       /* Maximum size of data USB packet */
        int max_packet_size;
 
        /* Device representing the USB interface */
index e983880703ea9a76b5d17224d9e7c407c8a16ea5..f41e34166d68bc1f853cb017905f8223df095660 100644 (file)
@@ -20,9 +20,6 @@
 
 #include "driver.h"
 
-/* number of URBs */
-#define LINE6_ISO_BUFFERS      2
-
 /*
        number of USB frames per URB
        The Line 6 Windows driver always transmits two frames per packet, but
@@ -31,7 +28,9 @@
 */
 #define LINE6_ISO_PACKETS      1
 
-/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
+/* in a "full speed" device (such as the PODxt Pro) this means 1ms,
+ *  for "high speed" it's 1/8ms
+ */
 #define LINE6_ISO_INTERVAL     1
 
 #define LINE6_IMPULSE_DEFAULT_PERIOD 100
index 1380facda4276b3c9b354e3633c3b68ffe151a19..6048d0fe4068108d7a9737addfc54bd7e4eee62f 100644 (file)
@@ -151,7 +151,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
                line6pcm->properties->rates.rats[0].num_min;
        const int frame_factor =
                line6pcm->properties->rates.rats[0].den *
-               (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
+               (line6pcm->line6->intervals_per_second / LINE6_ISO_INTERVAL);
        struct urb *urb_out;
 
        index = find_first_zero_bit(&line6pcm->out.active_urbs,