diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/usbaudio.c | 151 |
1 files changed, 65 insertions, 86 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a703d96bfcb4..2b4f916a0a9a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -41,6 +41,7 @@ | |||
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> | ||
44 | #include <linux/list.h> | 45 | #include <linux/list.h> |
45 | #include <linux/slab.h> | 46 | #include <linux/slab.h> |
46 | #include <linux/string.h> | 47 | #include <linux/string.h> |
@@ -129,8 +130,6 @@ struct snd_urb_ctx { | |||
129 | snd_usb_substream_t *subs; | 130 | snd_usb_substream_t *subs; |
130 | int index; /* index for urb array */ | 131 | int index; /* index for urb array */ |
131 | int packets; /* number of packets per urb */ | 132 | int packets; /* number of packets per urb */ |
132 | int transfer; /* transferred size */ | ||
133 | char *buf; /* buffer for capture */ | ||
134 | }; | 133 | }; |
135 | 134 | ||
136 | struct snd_urb_ops { | 135 | struct snd_urb_ops { |
@@ -168,9 +167,7 @@ struct snd_usb_substream { | |||
168 | 167 | ||
169 | unsigned int running: 1; /* running status */ | 168 | unsigned int running: 1; /* running status */ |
170 | 169 | ||
171 | unsigned int hwptr; /* free frame position in the buffer (only for playback) */ | ||
172 | unsigned int hwptr_done; /* processed frame position in the buffer */ | 170 | unsigned int hwptr_done; /* processed frame position in the buffer */ |
173 | unsigned int transfer_sched; /* scheduled frames since last period (for playback) */ | ||
174 | unsigned int transfer_done; /* processed frames since last period update */ | 171 | unsigned int transfer_done; /* processed frames since last period update */ |
175 | unsigned long active_mask; /* bitmask of active urbs */ | 172 | unsigned long active_mask; /* bitmask of active urbs */ |
176 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ | 173 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ |
@@ -179,12 +176,12 @@ struct snd_usb_substream { | |||
179 | snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ | 176 | snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ |
180 | snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ | 177 | snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ |
181 | char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ | 178 | char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ |
182 | char *tmpbuf; /* temporary buffer for playback */ | ||
183 | 179 | ||
184 | u64 formats; /* format bitmasks (all or'ed) */ | 180 | u64 formats; /* format bitmasks (all or'ed) */ |
185 | unsigned int num_formats; /* number of supported audio formats (list) */ | 181 | unsigned int num_formats; /* number of supported audio formats (list) */ |
186 | struct list_head fmt_list; /* format list */ | 182 | struct list_head fmt_list; /* format list */ |
187 | spinlock_t lock; | 183 | spinlock_t lock; |
184 | struct tasklet_struct start_period_elapsed; /* for start trigger */ | ||
188 | 185 | ||
189 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ | 186 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ |
190 | }; | 187 | }; |
@@ -320,7 +317,6 @@ static int prepare_capture_urb(snd_usb_substream_t *subs, | |||
320 | urb->iso_frame_desc[i].length = subs->curpacksize; | 317 | urb->iso_frame_desc[i].length = subs->curpacksize; |
321 | offs += subs->curpacksize; | 318 | offs += subs->curpacksize; |
322 | } | 319 | } |
323 | urb->transfer_buffer = ctx->buf; | ||
324 | urb->transfer_buffer_length = offs; | 320 | urb->transfer_buffer_length = offs; |
325 | urb->number_of_packets = ctx->packets; | 321 | urb->number_of_packets = ctx->packets; |
326 | #if 0 // for check | 322 | #if 0 // for check |
@@ -482,12 +478,10 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, | |||
482 | /* | 478 | /* |
483 | * prepare urb for playback data pipe | 479 | * prepare urb for playback data pipe |
484 | * | 480 | * |
485 | * we copy the data directly from the pcm buffer. | 481 | * Since a URB can handle only a single linear buffer, we must use double |
486 | * the current position to be copied is held in hwptr field. | 482 | * buffering when the data to be transferred overflows the buffer boundary. |
487 | * since a urb can handle only a single linear buffer, if the total | 483 | * To avoid inconsistencies when updating hwptr_done, we use double buffering |
488 | * transferred area overflows the buffer boundary, we cannot send | 484 | * for all URBs. |
489 | * it directly from the buffer. thus the data is once copied to | ||
490 | * a temporary buffer and urb points to that. | ||
491 | */ | 485 | */ |
492 | static int prepare_playback_urb(snd_usb_substream_t *subs, | 486 | static int prepare_playback_urb(snd_usb_substream_t *subs, |
493 | snd_pcm_runtime_t *runtime, | 487 | snd_pcm_runtime_t *runtime, |
@@ -496,6 +490,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
496 | int i, stride, offs; | 490 | int i, stride, offs; |
497 | unsigned int counts; | 491 | unsigned int counts; |
498 | unsigned long flags; | 492 | unsigned long flags; |
493 | int period_elapsed = 0; | ||
499 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | 494 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; |
500 | 495 | ||
501 | stride = runtime->frame_bits >> 3; | 496 | stride = runtime->frame_bits >> 3; |
@@ -520,21 +515,25 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
520 | urb->iso_frame_desc[i].length = counts * stride; | 515 | urb->iso_frame_desc[i].length = counts * stride; |
521 | offs += counts; | 516 | offs += counts; |
522 | urb->number_of_packets++; | 517 | urb->number_of_packets++; |
523 | subs->transfer_sched += counts; | 518 | subs->transfer_done += counts; |
524 | if (subs->transfer_sched >= runtime->period_size) { | 519 | if (subs->transfer_done >= runtime->period_size) { |
525 | subs->transfer_sched -= runtime->period_size; | 520 | subs->transfer_done -= runtime->period_size; |
521 | period_elapsed = 1; | ||
526 | if (subs->fmt_type == USB_FORMAT_TYPE_II) { | 522 | if (subs->fmt_type == USB_FORMAT_TYPE_II) { |
527 | if (subs->transfer_sched > 0) { | 523 | if (subs->transfer_done > 0) { |
528 | /* FIXME: fill-max mode is not supported yet */ | 524 | /* FIXME: fill-max mode is not |
529 | offs -= subs->transfer_sched; | 525 | * supported yet */ |
530 | counts -= subs->transfer_sched; | 526 | offs -= subs->transfer_done; |
531 | urb->iso_frame_desc[i].length = counts * stride; | 527 | counts -= subs->transfer_done; |
532 | subs->transfer_sched = 0; | 528 | urb->iso_frame_desc[i].length = |
529 | counts * stride; | ||
530 | subs->transfer_done = 0; | ||
533 | } | 531 | } |
534 | i++; | 532 | i++; |
535 | if (i < ctx->packets) { | 533 | if (i < ctx->packets) { |
536 | /* add a transfer delimiter */ | 534 | /* add a transfer delimiter */ |
537 | urb->iso_frame_desc[i].offset = offs * stride; | 535 | urb->iso_frame_desc[i].offset = |
536 | offs * stride; | ||
538 | urb->iso_frame_desc[i].length = 0; | 537 | urb->iso_frame_desc[i].length = 0; |
539 | urb->number_of_packets++; | 538 | urb->number_of_packets++; |
540 | } | 539 | } |
@@ -542,58 +541,55 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
542 | break; | 541 | break; |
543 | } | 542 | } |
544 | } | 543 | } |
545 | if (subs->hwptr + offs > runtime->buffer_size) { | 544 | if (subs->hwptr_done + offs > runtime->buffer_size) { |
546 | /* err, the transferred area goes over buffer boundary. | 545 | /* err, the transferred area goes over buffer boundary. */ |
547 | * copy the data to the temp buffer. | 546 | unsigned int len = runtime->buffer_size - subs->hwptr_done; |
548 | */ | 547 | memcpy(urb->transfer_buffer, |
549 | int len; | 548 | runtime->dma_area + subs->hwptr_done * stride, |
550 | len = runtime->buffer_size - subs->hwptr; | 549 | len * stride); |
551 | urb->transfer_buffer = subs->tmpbuf; | 550 | memcpy(urb->transfer_buffer + len * stride, |
552 | memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride); | 551 | runtime->dma_area, |
553 | memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride); | 552 | (offs - len) * stride); |
554 | subs->hwptr += offs; | ||
555 | subs->hwptr -= runtime->buffer_size; | ||
556 | } else { | 553 | } else { |
557 | /* set the buffer pointer */ | 554 | memcpy(urb->transfer_buffer, |
558 | urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; | 555 | runtime->dma_area + subs->hwptr_done * stride, |
559 | subs->hwptr += offs; | 556 | offs * stride); |
560 | if (subs->hwptr == runtime->buffer_size) | ||
561 | subs->hwptr = 0; | ||
562 | } | 557 | } |
558 | subs->hwptr_done += offs; | ||
559 | if (subs->hwptr_done >= runtime->buffer_size) | ||
560 | subs->hwptr_done -= runtime->buffer_size; | ||
563 | spin_unlock_irqrestore(&subs->lock, flags); | 561 | spin_unlock_irqrestore(&subs->lock, flags); |
564 | urb->transfer_buffer_length = offs * stride; | 562 | urb->transfer_buffer_length = offs * stride; |
565 | ctx->transfer = offs; | 563 | if (period_elapsed) { |
566 | 564 | if (likely(subs->running)) | |
565 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
566 | else | ||
567 | tasklet_hi_schedule(&subs->start_period_elapsed); | ||
568 | } | ||
567 | return 0; | 569 | return 0; |
568 | } | 570 | } |
569 | 571 | ||
570 | /* | 572 | /* |
571 | * process after playback data complete | 573 | * process after playback data complete |
572 | * | 574 | * - nothing to do |
573 | * update the current position and call callback if a period is processed. | ||
574 | */ | 575 | */ |
575 | static int retire_playback_urb(snd_usb_substream_t *subs, | 576 | static int retire_playback_urb(snd_usb_substream_t *subs, |
576 | snd_pcm_runtime_t *runtime, | 577 | snd_pcm_runtime_t *runtime, |
577 | struct urb *urb) | 578 | struct urb *urb) |
578 | { | 579 | { |
579 | unsigned long flags; | ||
580 | snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; | ||
581 | |||
582 | spin_lock_irqsave(&subs->lock, flags); | ||
583 | subs->transfer_done += ctx->transfer; | ||
584 | subs->hwptr_done += ctx->transfer; | ||
585 | ctx->transfer = 0; | ||
586 | if (subs->hwptr_done >= runtime->buffer_size) | ||
587 | subs->hwptr_done -= runtime->buffer_size; | ||
588 | if (subs->transfer_done >= runtime->period_size) { | ||
589 | subs->transfer_done -= runtime->period_size; | ||
590 | spin_unlock_irqrestore(&subs->lock, flags); | ||
591 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
592 | } else | ||
593 | spin_unlock_irqrestore(&subs->lock, flags); | ||
594 | return 0; | 580 | return 0; |
595 | } | 581 | } |
596 | 582 | ||
583 | /* | ||
584 | * Delay the snd_pcm_period_elapsed() call until after the start trigger | ||
585 | * callback so that we're not longer in the substream's lock. | ||
586 | */ | ||
587 | static void start_period_elapsed(unsigned long data) | ||
588 | { | ||
589 | snd_usb_substream_t *subs = (snd_usb_substream_t *)data; | ||
590 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
591 | } | ||
592 | |||
597 | 593 | ||
598 | /* | 594 | /* |
599 | */ | 595 | */ |
@@ -848,11 +844,10 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | |||
848 | static void release_urb_ctx(snd_urb_ctx_t *u) | 844 | static void release_urb_ctx(snd_urb_ctx_t *u) |
849 | { | 845 | { |
850 | if (u->urb) { | 846 | if (u->urb) { |
847 | kfree(u->urb->transfer_buffer); | ||
851 | usb_free_urb(u->urb); | 848 | usb_free_urb(u->urb); |
852 | u->urb = NULL; | 849 | u->urb = NULL; |
853 | } | 850 | } |
854 | kfree(u->buf); | ||
855 | u->buf = NULL; | ||
856 | } | 851 | } |
857 | 852 | ||
858 | /* | 853 | /* |
@@ -870,8 +865,6 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) | |||
870 | release_urb_ctx(&subs->dataurb[i]); | 865 | release_urb_ctx(&subs->dataurb[i]); |
871 | for (i = 0; i < SYNC_URBS; i++) | 866 | for (i = 0; i < SYNC_URBS; i++) |
872 | release_urb_ctx(&subs->syncurb[i]); | 867 | release_urb_ctx(&subs->syncurb[i]); |
873 | kfree(subs->tmpbuf); | ||
874 | subs->tmpbuf = NULL; | ||
875 | subs->nurbs = 0; | 868 | subs->nurbs = 0; |
876 | } | 869 | } |
877 | 870 | ||
@@ -923,24 +916,15 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
923 | urb_packs = 1; | 916 | urb_packs = 1; |
924 | urb_packs *= packs_per_ms; | 917 | urb_packs *= packs_per_ms; |
925 | 918 | ||
926 | /* allocate a temporary buffer for playback */ | ||
927 | if (is_playback) { | ||
928 | subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL); | ||
929 | if (! subs->tmpbuf) { | ||
930 | snd_printk(KERN_ERR "cannot malloc tmpbuf\n"); | ||
931 | return -ENOMEM; | ||
932 | } | ||
933 | } | ||
934 | |||
935 | /* decide how many packets to be used */ | 919 | /* decide how many packets to be used */ |
936 | if (is_playback) { | 920 | if (is_playback) { |
937 | unsigned int minsize; | 921 | unsigned int minsize; |
938 | /* determine how small a packet can be */ | 922 | /* determine how small a packet can be */ |
939 | minsize = (subs->freqn >> (16 - subs->datainterval)) | 923 | minsize = (subs->freqn >> (16 - subs->datainterval)) |
940 | * (frame_bits >> 3); | 924 | * (frame_bits >> 3); |
941 | /* with sync from device, assume it can be 25% lower */ | 925 | /* with sync from device, assume it can be 12% lower */ |
942 | if (subs->syncpipe) | 926 | if (subs->syncpipe) |
943 | minsize -= minsize >> 2; | 927 | minsize -= minsize >> 3; |
944 | minsize = max(minsize, 1u); | 928 | minsize = max(minsize, 1u); |
945 | total_packs = (period_bytes + minsize - 1) / minsize; | 929 | total_packs = (period_bytes + minsize - 1) / minsize; |
946 | /* round up to multiple of packs_per_ms */ | 930 | /* round up to multiple of packs_per_ms */ |
@@ -989,27 +973,22 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
989 | snd_urb_ctx_t *u = &subs->dataurb[i]; | 973 | snd_urb_ctx_t *u = &subs->dataurb[i]; |
990 | u->index = i; | 974 | u->index = i; |
991 | u->subs = subs; | 975 | u->subs = subs; |
992 | u->transfer = 0; | ||
993 | u->packets = npacks[i]; | 976 | u->packets = npacks[i]; |
994 | if (subs->fmt_type == USB_FORMAT_TYPE_II) | 977 | if (subs->fmt_type == USB_FORMAT_TYPE_II) |
995 | u->packets++; /* for transfer delimiter */ | 978 | u->packets++; /* for transfer delimiter */ |
996 | if (! is_playback) { | ||
997 | /* allocate a capture buffer per urb */ | ||
998 | u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL); | ||
999 | if (! u->buf) { | ||
1000 | release_substream_urbs(subs, 0); | ||
1001 | return -ENOMEM; | ||
1002 | } | ||
1003 | } | ||
1004 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); | 979 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); |
1005 | if (! u->urb) { | 980 | if (! u->urb) { |
1006 | release_substream_urbs(subs, 0); | 981 | release_substream_urbs(subs, 0); |
1007 | return -ENOMEM; | 982 | return -ENOMEM; |
1008 | } | 983 | } |
1009 | u->urb->dev = subs->dev; | 984 | u->urb->transfer_buffer = kmalloc(maxsize * u->packets, |
985 | GFP_KERNEL); | ||
986 | if (! u->urb->transfer_buffer) { | ||
987 | release_substream_urbs(subs, 0); | ||
988 | return -ENOMEM; | ||
989 | } | ||
1010 | u->urb->pipe = subs->datapipe; | 990 | u->urb->pipe = subs->datapipe; |
1011 | u->urb->transfer_flags = URB_ISO_ASAP; | 991 | u->urb->transfer_flags = URB_ISO_ASAP; |
1012 | u->urb->number_of_packets = u->packets; | ||
1013 | u->urb->interval = 1 << subs->datainterval; | 992 | u->urb->interval = 1 << subs->datainterval; |
1014 | u->urb->context = u; | 993 | u->urb->context = u; |
1015 | u->urb->complete = snd_usb_complete_callback(snd_complete_urb); | 994 | u->urb->complete = snd_usb_complete_callback(snd_complete_urb); |
@@ -1029,7 +1008,6 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
1029 | } | 1008 | } |
1030 | u->urb->transfer_buffer = subs->syncbuf + i * 4; | 1009 | u->urb->transfer_buffer = subs->syncbuf + i * 4; |
1031 | u->urb->transfer_buffer_length = 4; | 1010 | u->urb->transfer_buffer_length = 4; |
1032 | u->urb->dev = subs->dev; | ||
1033 | u->urb->pipe = subs->syncpipe; | 1011 | u->urb->pipe = subs->syncpipe; |
1034 | u->urb->transfer_flags = URB_ISO_ASAP; | 1012 | u->urb->transfer_flags = URB_ISO_ASAP; |
1035 | u->urb->number_of_packets = 1; | 1013 | u->urb->number_of_packets = 1; |
@@ -1386,9 +1364,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) | |||
1386 | subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); | 1364 | subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); |
1387 | 1365 | ||
1388 | /* reset the pointer */ | 1366 | /* reset the pointer */ |
1389 | subs->hwptr = 0; | ||
1390 | subs->hwptr_done = 0; | 1367 | subs->hwptr_done = 0; |
1391 | subs->transfer_sched = 0; | ||
1392 | subs->transfer_done = 0; | 1368 | subs->transfer_done = 0; |
1393 | subs->phase = 0; | 1369 | subs->phase = 0; |
1394 | 1370 | ||
@@ -2035,6 +2011,9 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat | |||
2035 | 2011 | ||
2036 | INIT_LIST_HEAD(&subs->fmt_list); | 2012 | INIT_LIST_HEAD(&subs->fmt_list); |
2037 | spin_lock_init(&subs->lock); | 2013 | spin_lock_init(&subs->lock); |
2014 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2015 | tasklet_init(&subs->start_period_elapsed, start_period_elapsed, | ||
2016 | (unsigned long)subs); | ||
2038 | 2017 | ||
2039 | subs->stream = as; | 2018 | subs->stream = as; |
2040 | subs->direction = stream; | 2019 | subs->direction = stream; |