diff options
Diffstat (limited to 'sound/usb/6fire/pcm.c')
-rw-r--r-- | sound/usb/6fire/pcm.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index c5b9cac37dc4..b5eb97fdc842 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -543,7 +543,7 @@ static snd_pcm_uframes_t usb6fire_pcm_pointer( snd_pcm_uframes_t ret; if (rt->panic || !sub) - return SNDRV_PCM_STATE_XRUN; + return SNDRV_PCM_POS_XRUN; spin_lock_irqsave(&sub->lock, flags); ret = sub->dma_off; @@ -582,6 +582,33 @@ static void usb6fire_pcm_init_urb(struct pcm_urb *urb, urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; } +static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) +{ + int i; + + for (i = 0; i < PCM_N_URBS; i++) { + rt->out_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB + * PCM_MAX_PACKET_SIZE, GFP_KERNEL); + if (!rt->out_urbs[i].buffer) + return -ENOMEM; + rt->in_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB + * PCM_MAX_PACKET_SIZE, GFP_KERNEL); + if (!rt->in_urbs[i].buffer) + return -ENOMEM; + } + return 0; +} + +static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt) +{ + int i; + + for (i = 0; i < PCM_N_URBS; i++) { + kfree(rt->out_urbs[i].buffer); + kfree(rt->in_urbs[i].buffer); + } +} + int usb6fire_pcm_init(struct sfire_chip *chip) { int i; @@ -593,6 +620,13 @@ int usb6fire_pcm_init(struct sfire_chip *chip) if (!rt) return -ENOMEM; + ret = usb6fire_pcm_buffers_init(rt); + if (ret) { + usb6fire_pcm_buffers_destroy(rt); + kfree(rt); + return ret; + } + rt->chip = chip; rt->stream_state = STREAM_DISABLED; rt->rate = ARRAY_SIZE(rates); @@ -614,6 +648,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip) ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm); if (ret < 0) { + usb6fire_pcm_buffers_destroy(rt); kfree(rt); snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n"); return ret; @@ -625,6 +660,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); if (ret) { + usb6fire_pcm_buffers_destroy(rt); kfree(rt); snd_printk(KERN_ERR PREFIX "error preallocating pcm buffers.\n"); @@ -639,17 +675,25 @@ int usb6fire_pcm_init(struct sfire_chip *chip) void usb6fire_pcm_abort(struct sfire_chip *chip) { struct pcm_runtime *rt = chip->pcm; + unsigned long flags; int i; if (rt) { rt->panic = true; - if (rt->playback.instance) + if (rt->playback.instance) { + snd_pcm_stream_lock_irqsave(rt->playback.instance, flags); snd_pcm_stop(rt->playback.instance, SNDRV_PCM_STATE_XRUN); - if (rt->capture.instance) + snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags); + } + + if (rt->capture.instance) { + snd_pcm_stream_lock_irqsave(rt->capture.instance, flags); snd_pcm_stop(rt->capture.instance, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags); + } for (i = 0; i < PCM_N_URBS; i++) { usb_poison_urb(&rt->in_urbs[i].instance); @@ -661,6 +705,9 @@ void usb6fire_pcm_abort(struct sfire_chip *chip) void usb6fire_pcm_destroy(struct sfire_chip *chip) { - kfree(chip->pcm); + struct pcm_runtime *rt = chip->pcm; + + usb6fire_pcm_buffers_destroy(rt); + kfree(rt); chip->pcm = NULL; } |