From 79faa2b048b23f28a24a7b232d8933cb53df95b7 Mon Sep 17 00:00:00 2001 From: Andrej Krutak Date: Sun, 18 Sep 2016 20:59:22 +0200 Subject: ALSA: line6: Add high-speed USB support 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 Signed-off-by: Takashi Iwai --- sound/usb/line6/capture.c | 10 +++++++++- sound/usb/line6/driver.c | 15 ++++++++++----- sound/usb/line6/driver.h | 15 ++++++++++++--- sound/usb/line6/pcm.h | 7 +++---- sound/usb/line6/playback.c | 2 +- 5 files changed, 35 insertions(+), 14 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index c2808a0b771a..596bc53d0775 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -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; diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 527c4086f6fc..14032d96da67 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -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) { diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index 43dd1d06b5fa..a55eb8871b51 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -18,7 +18,13 @@ #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 */ diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index e983880703ea..f41e34166d68 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h @@ -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 diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 1380facda427..6048d0fe4068 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -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, -- cgit v1.2.3