aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-07-13 07:48:36 -0400
committerTakashi Iwai <tiwai@suse.de>2009-07-15 05:56:41 -0400
commita65dd997b3cf057f6524466cf8dfb8382c132bd5 (patch)
treef5463308ba24a10266ae828ed869500c6f282fd1
parented4affa53229701be7be4f7f84ba84164135d7e8 (diff)
sound: usb-audio: add MIDI drain callback
When draining, instead of waiting for fifty milliseconds, just wait for the currently active URBs to complete. This cuts the usual waiting time down to one USB frame, or zero in the common case when there is no URB. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/usbmidi.c79
1 files changed, 60 insertions, 19 deletions
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 32d70cc046e7..0eff19ceb7e1 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -45,6 +45,7 @@
45#include <linux/slab.h> 45#include <linux/slab.h>
46#include <linux/timer.h> 46#include <linux/timer.h>
47#include <linux/usb.h> 47#include <linux/usb.h>
48#include <linux/wait.h>
48#include <sound/core.h> 49#include <sound/core.h>
49#include <sound/rawmidi.h> 50#include <sound/rawmidi.h>
50#include <sound/asequencer.h> 51#include <sound/asequencer.h>
@@ -124,9 +125,10 @@ struct snd_usb_midi_out_endpoint {
124 struct snd_usb_midi_out_endpoint *ep; 125 struct snd_usb_midi_out_endpoint *ep;
125 } urbs[OUTPUT_URBS]; 126 } urbs[OUTPUT_URBS];
126 unsigned int active_urbs; 127 unsigned int active_urbs;
128 unsigned int drain_urbs;
127 int max_transfer; /* size of urb buffer */ 129 int max_transfer; /* size of urb buffer */
128 struct tasklet_struct tasklet; 130 struct tasklet_struct tasklet;
129 131 unsigned int next_urb;
130 spinlock_t buffer_lock; 132 spinlock_t buffer_lock;
131 133
132 struct usbmidi_out_port { 134 struct usbmidi_out_port {
@@ -145,6 +147,8 @@ struct snd_usb_midi_out_endpoint {
145 uint8_t data[2]; 147 uint8_t data[2];
146 } ports[0x10]; 148 } ports[0x10];
147 int current_port; 149 int current_port;
150
151 wait_queue_head_t drain_wait;
148}; 152};
149 153
150struct snd_usb_midi_in_endpoint { 154struct snd_usb_midi_in_endpoint {
@@ -259,9 +263,15 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
259{ 263{
260 struct out_urb_context *context = urb->context; 264 struct out_urb_context *context = urb->context;
261 struct snd_usb_midi_out_endpoint* ep = context->ep; 265 struct snd_usb_midi_out_endpoint* ep = context->ep;
266 unsigned int urb_index;
262 267
263 spin_lock(&ep->buffer_lock); 268 spin_lock(&ep->buffer_lock);
264 ep->active_urbs &= ~(1 << (context - ep->urbs)); 269 urb_index = context - ep->urbs;
270 ep->active_urbs &= ~(1 << urb_index);
271 if (unlikely(ep->drain_urbs)) {
272 ep->drain_urbs &= ~(1 << urb_index);
273 wake_up(&ep->drain_wait);
274 }
265 spin_unlock(&ep->buffer_lock); 275 spin_unlock(&ep->buffer_lock);
266 if (urb->status < 0) { 276 if (urb->status < 0) {
267 int err = snd_usbmidi_urb_error(urb->status); 277 int err = snd_usbmidi_urb_error(urb->status);
@@ -291,28 +301,28 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep)
291 return; 301 return;
292 } 302 }
293 303
304 urb_index = ep->next_urb;
294 for (;;) { 305 for (;;) {
295 urb = NULL; 306 if (!(ep->active_urbs & (1 << urb_index))) {
296 for (urb_index = 0; urb_index < OUTPUT_URBS; ++urb_index) 307 urb = ep->urbs[urb_index].urb;
297 if (!(ep->active_urbs & (1 << urb_index))) { 308 urb->transfer_buffer_length = 0;
298 urb = ep->urbs[urb_index].urb; 309 ep->umidi->usb_protocol_ops->output(ep, urb);
310 if (urb->transfer_buffer_length == 0)
299 break; 311 break;
300 }
301 if (!urb)
302 break;
303
304 urb->transfer_buffer_length = 0;
305 ep->umidi->usb_protocol_ops->output(ep, urb);
306 if (urb->transfer_buffer_length == 0)
307 break;
308 312
309 dump_urb("sending", urb->transfer_buffer, 313 dump_urb("sending", urb->transfer_buffer,
310 urb->transfer_buffer_length); 314 urb->transfer_buffer_length);
311 urb->dev = ep->umidi->chip->dev; 315 urb->dev = ep->umidi->chip->dev;
312 if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) 316 if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0)
317 break;
318 ep->active_urbs |= 1 << urb_index;
319 }
320 if (++urb_index >= OUTPUT_URBS)
321 urb_index = 0;
322 if (urb_index == ep->next_urb)
313 break; 323 break;
314 ep->active_urbs |= 1 << urb_index;
315 } 324 }
325 ep->next_urb = urb_index;
316 spin_unlock_irqrestore(&ep->buffer_lock, flags); 326 spin_unlock_irqrestore(&ep->buffer_lock, flags);
317} 327}
318 328
@@ -913,6 +923,35 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
913 } 923 }
914} 924}
915 925
926static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
927{
928 struct usbmidi_out_port* port = substream->runtime->private_data;
929 struct snd_usb_midi_out_endpoint *ep = port->ep;
930 unsigned int drain_urbs;
931 DEFINE_WAIT(wait);
932 long timeout = msecs_to_jiffies(50);
933
934 /*
935 * The substream buffer is empty, but some data might still be in the
936 * currently active URBs, so we have to wait for those to complete.
937 */
938 spin_lock_irq(&ep->buffer_lock);
939 drain_urbs = ep->active_urbs;
940 if (drain_urbs) {
941 ep->drain_urbs |= drain_urbs;
942 do {
943 prepare_to_wait(&ep->drain_wait, &wait,
944 TASK_UNINTERRUPTIBLE);
945 spin_unlock_irq(&ep->buffer_lock);
946 timeout = schedule_timeout(timeout);
947 spin_lock_irq(&ep->buffer_lock);
948 drain_urbs &= ep->drain_urbs;
949 } while (drain_urbs && timeout);
950 finish_wait(&ep->drain_wait, &wait);
951 }
952 spin_unlock_irq(&ep->buffer_lock);
953}
954
916static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) 955static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
917{ 956{
918 return 0; 957 return 0;
@@ -937,6 +976,7 @@ static struct snd_rawmidi_ops snd_usbmidi_output_ops = {
937 .open = snd_usbmidi_output_open, 976 .open = snd_usbmidi_output_open,
938 .close = snd_usbmidi_output_close, 977 .close = snd_usbmidi_output_close,
939 .trigger = snd_usbmidi_output_trigger, 978 .trigger = snd_usbmidi_output_trigger,
979 .drain = snd_usbmidi_output_drain,
940}; 980};
941 981
942static struct snd_rawmidi_ops snd_usbmidi_input_ops = { 982static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
@@ -1103,6 +1143,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
1103 1143
1104 spin_lock_init(&ep->buffer_lock); 1144 spin_lock_init(&ep->buffer_lock);
1105 tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); 1145 tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
1146 init_waitqueue_head(&ep->drain_wait);
1106 1147
1107 for (i = 0; i < 0x10; ++i) 1148 for (i = 0; i < 0x10; ++i)
1108 if (ep_info->out_cables & (1 << i)) { 1149 if (ep_info->out_cables & (1 << i)) {