diff options
Diffstat (limited to 'linux/drivers/media/video/em28xx/em28xx-audio.c')
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-audio.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index 34c494d68..fcf21a614 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -62,12 +62,19 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) int i; dprintk("Stopping isoc\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_unlink_urb(dev->adev.urb[i]); + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + if (!irqs_disabled()) + usb_kill_urb(dev->adev.urb[i]); + else + usb_unlink_urb(dev->adev.urb[i]); usb_free_urb(dev->adev.urb[i]); dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; } + dev->isoc_ctl.num_bufs = 0; return 0; } @@ -172,6 +179,8 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) dprintk("Starting isoc transfers\n"); + dev->isoc_ctl.num_bufs = 0; + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { struct urb *urb; int j, k; @@ -213,10 +222,19 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { - em28xx_isoc_audio_deinit(dev); + if (dev->isoc_ctl.num_bufs == 0) { + usb_free_urb(dev->adev.urb[i]); + dev->adev.urb[i] = NULL; + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; + } else + em28xx_isoc_audio_deinit(dev); return errCode; } + mutex_lock(&dev->lock); + dev->isoc_ctl.num_bufs++; + mutex_unlock(&dev->lock); } return 0; @@ -458,11 +476,15 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) #endif { - struct em28xx *dev; + unsigned long flags; + struct em28xx *dev; snd_pcm_uframes_t hwptr_done; + dev = snd_pcm_substream_chip(substream); + spin_lock_irqsave(&dev->adev.slock, flags); hwptr_done = dev->adev.hwptr_done_capture; + spin_unlock_irqrestore(&dev->adev.slock, flags); return hwptr_done; } |