[media] em28xx-audio: allocate URBs at device driver init
authorMauro Carvalho Chehab <mchehab@redhat.com>
Sun, 29 Dec 2013 00:16:26 +0000 (21:16 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Fri, 10 Jan 2014 08:01:47 +0000 (06:01 -0200)
Instead of allocating/deallocating URBs and transfer buffers
every time stream is started/stopped, just do it once.

That reduces the memory allocation pressure and makes the
code that start/stop streaming a way simpler.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/usb/em28xx/em28xx-audio.c

index e512043..30ee389 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
  *
- *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
  *     - Port to work with the in-kernel driver
  *     - Cleanups, fixes, alsa-controls, etc.
  *
@@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
                        usb_kill_urb(urb);
                else
                        usb_unlink_urb(urb);
-
-               usb_free_coherent(dev->udev,
-                                 urb->transfer_buffer_length,
-                                 dev->adev.transfer_buffer[i],
-                                 urb->transfer_dma);
-
-               dev->adev.transfer_buffer[i] = NULL;
-
-               usb_free_urb(urb);
-               dev->adev.urb[i] = NULL;
        }
 
        return 0;
@@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
 static int em28xx_init_audio_isoc(struct em28xx *dev)
 {
        int       i, errCode;
-       const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
-                           EM28XX_AUDIO_MAX_PACKET_SIZE;
 
        dprintk("Starting isoc transfers\n");
 
+       /* Start streaming */
        for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-               struct urb *urb;
-               int j, k;
-               void *buf;
-
-               urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
-               if (!urb) {
-                       em28xx_errdev("usb_alloc_urb failed!\n");
-                       for (j = 0; j < i; j++) {
-                               usb_free_urb(dev->adev.urb[j]);
-                               kfree(dev->adev.transfer_buffer[j]);
-                       }
-                       return -ENOMEM;
-               }
-
-               buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
-                                        &urb->transfer_dma);
-               if (!buf)
-                       return -ENOMEM;
-               dev->adev.transfer_buffer[i] = buf;
-               memset(buf, 0x80, sb_size);
-
-               urb->dev = dev->udev;
-               urb->context = dev;
-               urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
-               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_buffer = dev->adev.transfer_buffer[i];
-               urb->interval = 1;
-               urb->complete = em28xx_audio_isocirq;
-               urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
-               urb->transfer_buffer_length = sb_size;
-
-               for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
-                            j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length =
-                           EM28XX_AUDIO_MAX_PACKET_SIZE;
-               }
-               dev->adev.urb[i] = urb;
-       }
+               memset(dev->adev.transfer_buffer[i], 0x80,
+                      dev->adev.urb[i]->transfer_buffer_length);
 
-       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
                errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
                if (errCode) {
                        em28xx_errdev("submit of audio urb failed\n");
@@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
        .page      = snd_pcm_get_vmalloc_page,
 };
 
+static void em28xx_audio_free_urb(struct em28xx *dev)
+{
+       int i;
+
+       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+               struct urb *urb = dev->adev.urb[i];
+
+               if (!dev->adev.urb[i])
+                       continue;
+
+               usb_free_coherent(dev->udev,
+                                 urb->transfer_buffer_length,
+                                 dev->adev.transfer_buffer[i],
+                                 urb->transfer_dma);
+
+               usb_free_urb(urb);
+               dev->adev.urb[i] = NULL;
+               dev->adev.transfer_buffer[i] = NULL;
+       }
+}
+
 static int em28xx_audio_init(struct em28xx *dev)
 {
        struct em28xx_audio *adev = &dev->adev;
        struct snd_pcm      *pcm;
        struct snd_card     *card;
        static int          devnr;
-       int                 err;
+       int                 err, i;
+       const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+                           EM28XX_AUDIO_MAX_PACKET_SIZE;
 
        if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
                /* This device does not support the extension (in this case
@@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 
        printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
                         "Rechberger\n");
-       printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+       printk(KERN_INFO
+              "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
 
        err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
                              &card);
@@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
                em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
        }
 
+       /* Alloc URB and transfer buffers */
+       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+               struct urb *urb;
+               int j, k;
+               void *buf;
+
+               urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+               if (!urb) {
+                       em28xx_errdev("usb_alloc_urb failed!\n");
+                       em28xx_audio_free_urb(dev);
+                       return -ENOMEM;
+               }
+               dev->adev.urb[i] = urb;
+
+               buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
+                                        &urb->transfer_dma);
+               if (!buf) {
+                       em28xx_errdev("usb_alloc_coherent failed!\n");
+                       em28xx_audio_free_urb(dev);
+                       return -ENOMEM;
+               }
+               dev->adev.transfer_buffer[i] = buf;
+
+               urb->dev = dev->udev;
+               urb->context = dev;
+               urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer = dev->adev.transfer_buffer[i];
+               urb->interval = 1;
+               urb->complete = em28xx_audio_isocirq;
+               urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+               urb->transfer_buffer_length = sb_size;
+
+               for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+                            j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length =
+                           EM28XX_AUDIO_MAX_PACKET_SIZE;
+               }
+       }
+
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
@@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
                return 0;
        }
 
+       em28xx_audio_free_urb(dev);
+
        if (dev->adev.sndcard) {
                snd_card_free(dev->adev.sndcard);
                dev->adev.sndcard = NULL;