diff options
Diffstat (limited to 'sound/usb/caiaq/audio.c')
-rw-r--r-- | sound/usb/caiaq/audio.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index d0d493ca28ae..2cf87f5afed4 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c | |||
@@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) | |||
139 | 139 | ||
140 | for (i = 0; i < N_URBS; i++) { | 140 | for (i = 0; i < N_URBS; i++) { |
141 | usb_kill_urb(dev->data_urbs_in[i]); | 141 | usb_kill_urb(dev->data_urbs_in[i]); |
142 | usb_kill_urb(dev->data_urbs_out[i]); | 142 | |
143 | if (test_bit(i, &dev->outurb_active_mask)) | ||
144 | usb_kill_urb(dev->data_urbs_out[i]); | ||
143 | } | 145 | } |
146 | |||
147 | dev->outurb_active_mask = 0; | ||
144 | } | 148 | } |
145 | 149 | ||
146 | static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) | 150 | static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) |
@@ -612,8 +616,9 @@ static void read_completed(struct urb *urb) | |||
612 | { | 616 | { |
613 | struct snd_usb_caiaq_cb_info *info = urb->context; | 617 | struct snd_usb_caiaq_cb_info *info = urb->context; |
614 | struct snd_usb_caiaqdev *dev; | 618 | struct snd_usb_caiaqdev *dev; |
615 | struct urb *out; | 619 | struct urb *out = NULL; |
616 | int frame, len, send_it = 0, outframe = 0; | 620 | int i, frame, len, send_it = 0, outframe = 0; |
621 | size_t offset = 0; | ||
617 | 622 | ||
618 | if (urb->status || !info) | 623 | if (urb->status || !info) |
619 | return; | 624 | return; |
@@ -623,7 +628,17 @@ static void read_completed(struct urb *urb) | |||
623 | if (!dev->streaming) | 628 | if (!dev->streaming) |
624 | return; | 629 | return; |
625 | 630 | ||
626 | out = dev->data_urbs_out[info->index]; | 631 | /* find an unused output urb that is unused */ |
632 | for (i = 0; i < N_URBS; i++) | ||
633 | if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) { | ||
634 | out = dev->data_urbs_out[i]; | ||
635 | break; | ||
636 | } | ||
637 | |||
638 | if (!out) { | ||
639 | log("Unable to find an output urb to use\n"); | ||
640 | goto requeue; | ||
641 | } | ||
627 | 642 | ||
628 | /* read the recently received packet and send back one which has | 643 | /* read the recently received packet and send back one which has |
629 | * the same layout */ | 644 | * the same layout */ |
@@ -634,7 +649,8 @@ static void read_completed(struct urb *urb) | |||
634 | len = urb->iso_frame_desc[outframe].actual_length; | 649 | len = urb->iso_frame_desc[outframe].actual_length; |
635 | out->iso_frame_desc[outframe].length = len; | 650 | out->iso_frame_desc[outframe].length = len; |
636 | out->iso_frame_desc[outframe].actual_length = 0; | 651 | out->iso_frame_desc[outframe].actual_length = 0; |
637 | out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; | 652 | out->iso_frame_desc[outframe].offset = offset; |
653 | offset += len; | ||
638 | 654 | ||
639 | if (len > 0) { | 655 | if (len > 0) { |
640 | spin_lock(&dev->spinlock); | 656 | spin_lock(&dev->spinlock); |
@@ -650,11 +666,15 @@ static void read_completed(struct urb *urb) | |||
650 | } | 666 | } |
651 | 667 | ||
652 | if (send_it) { | 668 | if (send_it) { |
653 | out->number_of_packets = FRAMES_PER_URB; | 669 | out->number_of_packets = outframe; |
654 | out->transfer_flags = URB_ISO_ASAP; | 670 | out->transfer_flags = URB_ISO_ASAP; |
655 | usb_submit_urb(out, GFP_ATOMIC); | 671 | usb_submit_urb(out, GFP_ATOMIC); |
672 | } else { | ||
673 | struct snd_usb_caiaq_cb_info *oinfo = out->context; | ||
674 | clear_bit(oinfo->index, &dev->outurb_active_mask); | ||
656 | } | 675 | } |
657 | 676 | ||
677 | requeue: | ||
658 | /* re-submit inbound urb */ | 678 | /* re-submit inbound urb */ |
659 | for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 679 | for (frame = 0; frame < FRAMES_PER_URB; frame++) { |
660 | urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; | 680 | urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; |
@@ -676,6 +696,8 @@ static void write_completed(struct urb *urb) | |||
676 | dev->output_running = 1; | 696 | dev->output_running = 1; |
677 | wake_up(&dev->prepare_wait_queue); | 697 | wake_up(&dev->prepare_wait_queue); |
678 | } | 698 | } |
699 | |||
700 | clear_bit(info->index, &dev->outurb_active_mask); | ||
679 | } | 701 | } |
680 | 702 | ||
681 | static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) | 703 | static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) |
@@ -827,6 +849,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | |||
827 | if (!dev->data_cb_info) | 849 | if (!dev->data_cb_info) |
828 | return -ENOMEM; | 850 | return -ENOMEM; |
829 | 851 | ||
852 | dev->outurb_active_mask = 0; | ||
853 | BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8)); | ||
854 | |||
830 | for (i = 0; i < N_URBS; i++) { | 855 | for (i = 0; i < N_URBS; i++) { |
831 | dev->data_cb_info[i].dev = dev; | 856 | dev->data_cb_info[i].dev = dev; |
832 | dev->data_cb_info[i].index = i; | 857 | dev->data_cb_info[i].index = i; |