1
0
Fork 0

[media] em28xx-audio: allocate URBs at device driver init

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>
hifive-unleashed-5.1
Mauro Carvalho Chehab 2013-12-28 21:16:26 -03:00 committed by Mauro Carvalho Chehab
parent 46c704d77f
commit f5f894d19e
1 changed files with 73 additions and 55 deletions

View 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;
memset(dev->adev.transfer_buffer[i], 0x80,
dev->adev.urb[i]->transfer_buffer_length);
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;
}
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;