diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/usbmidi.c | 79 |
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 | ||
150 | struct snd_usb_midi_in_endpoint { | 154 | struct 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 | ||
926 | static 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 | |||
916 | static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) | 955 | static 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 | ||
942 | static struct snd_rawmidi_ops snd_usbmidi_input_ops = { | 982 | static 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)) { |