diff options
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r-- | sound/usb/usbaudio.c | 100 |
1 files changed, 62 insertions, 38 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8818918c4237..99dae024b640 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <sound/driver.h> | 41 | #include <sound/driver.h> |
42 | #include <linux/bitops.h> | 42 | #include <linux/bitops.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | ||
45 | #include <linux/list.h> | 44 | #include <linux/list.h> |
46 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
47 | #include <linux/string.h> | 46 | #include <linux/string.h> |
@@ -185,7 +184,6 @@ struct snd_usb_substream { | |||
185 | unsigned int num_formats; /* number of supported audio formats (list) */ | 184 | unsigned int num_formats; /* number of supported audio formats (list) */ |
186 | struct list_head fmt_list; /* format list */ | 185 | struct list_head fmt_list; /* format list */ |
187 | spinlock_t lock; | 186 | spinlock_t lock; |
188 | struct tasklet_struct start_period_elapsed; /* for start trigger */ | ||
189 | 187 | ||
190 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ | 188 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ |
191 | }; | 189 | }; |
@@ -480,6 +478,28 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, | |||
480 | } | 478 | } |
481 | 479 | ||
482 | /* | 480 | /* |
481 | * Prepare urb for streaming before playback starts. | ||
482 | * | ||
483 | * We don't care about (or have) any data, so we just send a transfer delimiter. | ||
484 | */ | ||
485 | static int prepare_startup_playback_urb(snd_usb_substream_t *subs, | ||
486 | snd_pcm_runtime_t *runtime, | ||
487 | struct urb *urb) | ||
488 | { | ||
489 | unsigned int i; | ||
490 | snd_urb_ctx_t *ctx = urb->context; | ||
491 | |||
492 | urb->dev = ctx->subs->dev; | ||
493 | urb->number_of_packets = subs->packs_per_ms; | ||
494 | for (i = 0; i < subs->packs_per_ms; ++i) { | ||
495 | urb->iso_frame_desc[i].offset = 0; | ||
496 | urb->iso_frame_desc[i].length = 0; | ||
497 | } | ||
498 | urb->transfer_buffer_length = 0; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | /* | ||
483 | * prepare urb for playback data pipe | 503 | * prepare urb for playback data pipe |
484 | * | 504 | * |
485 | * Since a URB can handle only a single linear buffer, we must use double | 505 | * Since a URB can handle only a single linear buffer, we must use double |
@@ -568,12 +588,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
568 | subs->hwptr_done -= runtime->buffer_size; | 588 | subs->hwptr_done -= runtime->buffer_size; |
569 | spin_unlock_irqrestore(&subs->lock, flags); | 589 | spin_unlock_irqrestore(&subs->lock, flags); |
570 | urb->transfer_buffer_length = offs * stride; | 590 | urb->transfer_buffer_length = offs * stride; |
571 | if (period_elapsed) { | 591 | if (period_elapsed) |
572 | if (likely(subs->running)) | 592 | snd_pcm_period_elapsed(subs->pcm_substream); |
573 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
574 | else | ||
575 | tasklet_hi_schedule(&subs->start_period_elapsed); | ||
576 | } | ||
577 | return 0; | 593 | return 0; |
578 | } | 594 | } |
579 | 595 | ||
@@ -588,22 +604,12 @@ static int retire_playback_urb(snd_usb_substream_t *subs, | |||
588 | return 0; | 604 | return 0; |
589 | } | 605 | } |
590 | 606 | ||
591 | /* | ||
592 | * Delay the snd_pcm_period_elapsed() call until after the start trigger | ||
593 | * callback so that we're not longer in the substream's lock. | ||
594 | */ | ||
595 | static void start_period_elapsed(unsigned long data) | ||
596 | { | ||
597 | snd_usb_substream_t *subs = (snd_usb_substream_t *)data; | ||
598 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
599 | } | ||
600 | |||
601 | 607 | ||
602 | /* | 608 | /* |
603 | */ | 609 | */ |
604 | static struct snd_urb_ops audio_urb_ops[2] = { | 610 | static struct snd_urb_ops audio_urb_ops[2] = { |
605 | { | 611 | { |
606 | .prepare = prepare_playback_urb, | 612 | .prepare = prepare_startup_playback_urb, |
607 | .retire = retire_playback_urb, | 613 | .retire = retire_playback_urb, |
608 | .prepare_sync = prepare_playback_sync_urb, | 614 | .prepare_sync = prepare_playback_sync_urb, |
609 | .retire_sync = retire_playback_sync_urb, | 615 | .retire_sync = retire_playback_sync_urb, |
@@ -618,7 +624,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { | |||
618 | 624 | ||
619 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { | 625 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { |
620 | { | 626 | { |
621 | .prepare = prepare_playback_urb, | 627 | .prepare = prepare_startup_playback_urb, |
622 | .retire = retire_playback_urb, | 628 | .retire = retire_playback_urb, |
623 | .prepare_sync = prepare_playback_sync_urb_hs, | 629 | .prepare_sync = prepare_playback_sync_urb_hs, |
624 | .retire_sync = retire_playback_sync_urb_hs, | 630 | .retire_sync = retire_playback_sync_urb_hs, |
@@ -863,25 +869,40 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream) | |||
863 | 869 | ||
864 | 870 | ||
865 | /* | 871 | /* |
866 | * start/stop substream | 872 | * start/stop playback substream |
867 | */ | 873 | */ |
868 | static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | 874 | static int snd_usb_pcm_playback_trigger(snd_pcm_substream_t *substream, |
875 | int cmd) | ||
869 | { | 876 | { |
870 | snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; | 877 | snd_usb_substream_t *subs = substream->runtime->private_data; |
871 | int err; | ||
872 | 878 | ||
873 | switch (cmd) { | 879 | switch (cmd) { |
874 | case SNDRV_PCM_TRIGGER_START: | 880 | case SNDRV_PCM_TRIGGER_START: |
875 | err = start_urbs(subs, substream->runtime); | 881 | subs->ops.prepare = prepare_playback_urb; |
876 | break; | 882 | return 0; |
877 | case SNDRV_PCM_TRIGGER_STOP: | 883 | case SNDRV_PCM_TRIGGER_STOP: |
878 | err = deactivate_urbs(subs, 0, 0); | 884 | return deactivate_urbs(subs, 0, 0); |
879 | break; | ||
880 | default: | 885 | default: |
881 | err = -EINVAL; | 886 | return -EINVAL; |
882 | break; | 887 | } |
888 | } | ||
889 | |||
890 | /* | ||
891 | * start/stop capture substream | ||
892 | */ | ||
893 | static int snd_usb_pcm_capture_trigger(snd_pcm_substream_t *substream, | ||
894 | int cmd) | ||
895 | { | ||
896 | snd_usb_substream_t *subs = substream->runtime->private_data; | ||
897 | |||
898 | switch (cmd) { | ||
899 | case SNDRV_PCM_TRIGGER_START: | ||
900 | return start_urbs(subs, substream->runtime); | ||
901 | case SNDRV_PCM_TRIGGER_STOP: | ||
902 | return deactivate_urbs(subs, 0, 0); | ||
903 | default: | ||
904 | return -EINVAL; | ||
883 | } | 905 | } |
884 | return err < 0 ? err : 0; | ||
885 | } | 906 | } |
886 | 907 | ||
887 | 908 | ||
@@ -1413,7 +1434,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream) | |||
1413 | static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) | 1434 | static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) |
1414 | { | 1435 | { |
1415 | snd_pcm_runtime_t *runtime = substream->runtime; | 1436 | snd_pcm_runtime_t *runtime = substream->runtime; |
1416 | snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; | 1437 | snd_usb_substream_t *subs = runtime->private_data; |
1417 | 1438 | ||
1418 | if (! subs->cur_audiofmt) { | 1439 | if (! subs->cur_audiofmt) { |
1419 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); | 1440 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); |
@@ -1433,7 +1454,13 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) | |||
1433 | deactivate_urbs(subs, 0, 1); | 1454 | deactivate_urbs(subs, 0, 1); |
1434 | wait_clear_urbs(subs); | 1455 | wait_clear_urbs(subs); |
1435 | 1456 | ||
1436 | return 0; | 1457 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
1458 | * updates for all URBs would happen at the same time when starting */ | ||
1459 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1460 | subs->ops.prepare = prepare_startup_playback_urb; | ||
1461 | return start_urbs(subs, runtime); | ||
1462 | } else | ||
1463 | return 0; | ||
1437 | } | 1464 | } |
1438 | 1465 | ||
1439 | static snd_pcm_hardware_t snd_usb_playback = | 1466 | static snd_pcm_hardware_t snd_usb_playback = |
@@ -1847,7 +1874,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = { | |||
1847 | .hw_params = snd_usb_hw_params, | 1874 | .hw_params = snd_usb_hw_params, |
1848 | .hw_free = snd_usb_hw_free, | 1875 | .hw_free = snd_usb_hw_free, |
1849 | .prepare = snd_usb_pcm_prepare, | 1876 | .prepare = snd_usb_pcm_prepare, |
1850 | .trigger = snd_usb_pcm_trigger, | 1877 | .trigger = snd_usb_pcm_playback_trigger, |
1851 | .pointer = snd_usb_pcm_pointer, | 1878 | .pointer = snd_usb_pcm_pointer, |
1852 | .page = snd_pcm_get_vmalloc_page, | 1879 | .page = snd_pcm_get_vmalloc_page, |
1853 | }; | 1880 | }; |
@@ -1859,7 +1886,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = { | |||
1859 | .hw_params = snd_usb_hw_params, | 1886 | .hw_params = snd_usb_hw_params, |
1860 | .hw_free = snd_usb_hw_free, | 1887 | .hw_free = snd_usb_hw_free, |
1861 | .prepare = snd_usb_pcm_prepare, | 1888 | .prepare = snd_usb_pcm_prepare, |
1862 | .trigger = snd_usb_pcm_trigger, | 1889 | .trigger = snd_usb_pcm_capture_trigger, |
1863 | .pointer = snd_usb_pcm_pointer, | 1890 | .pointer = snd_usb_pcm_pointer, |
1864 | .page = snd_pcm_get_vmalloc_page, | 1891 | .page = snd_pcm_get_vmalloc_page, |
1865 | }; | 1892 | }; |
@@ -2078,9 +2105,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat | |||
2078 | 2105 | ||
2079 | INIT_LIST_HEAD(&subs->fmt_list); | 2106 | INIT_LIST_HEAD(&subs->fmt_list); |
2080 | spin_lock_init(&subs->lock); | 2107 | spin_lock_init(&subs->lock); |
2081 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2082 | tasklet_init(&subs->start_period_elapsed, start_period_elapsed, | ||
2083 | (unsigned long)subs); | ||
2084 | 2108 | ||
2085 | subs->stream = as; | 2109 | subs->stream = as; |
2086 | subs->direction = stream; | 2110 | subs->direction = stream; |