Files
media_build/backports/v5.5_alsa_pcm_api_updates.patch
CrazyCat 1995c153cf Update backport patches up to 5.19.
Drop support for <4.9.
2023-03-18 23:29:21 +02:00

887 lines
27 KiB
Diff

diff --git b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
index 9e7504e3cfd8..38d00935a292 100644
--- b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
+++ a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <media/v4l2-device.h>
@@ -237,6 +238,54 @@ static int snd_cobalt_pcm_capture_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_cobalt_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+static int snd_cobalt_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ dprintk("%s called\n", __func__);
+
+ return snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int snd_cobalt_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ if (substream->runtime->dma_area) {
+ dprintk("freeing pcm capture region\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
static int snd_cobalt_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream);
@@ -441,20 +490,36 @@ snd_pcm_uframes_t snd_cobalt_pcm_pb_pointer(struct snd_pcm_substream *substream)
substream->runtime->buffer_size;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
static const struct snd_pcm_ops snd_cobalt_pcm_capture_ops = {
.open = snd_cobalt_pcm_capture_open,
.close = snd_cobalt_pcm_capture_close,
+ .ioctl = snd_cobalt_pcm_ioctl,
+ .hw_params = snd_cobalt_pcm_hw_params,
+ .hw_free = snd_cobalt_pcm_hw_free,
.prepare = snd_cobalt_pcm_prepare,
.trigger = snd_cobalt_pcm_trigger,
.pointer = snd_cobalt_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
static const struct snd_pcm_ops snd_cobalt_pcm_playback_ops = {
.open = snd_cobalt_pcm_playback_open,
.close = snd_cobalt_pcm_playback_close,
+ .ioctl = snd_cobalt_pcm_ioctl,
+ .hw_params = snd_cobalt_pcm_hw_params,
+ .hw_free = snd_cobalt_pcm_hw_free,
.prepare = snd_cobalt_pcm_pb_prepare,
.trigger = snd_cobalt_pcm_pb_trigger,
.pointer = snd_cobalt_pcm_pb_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc)
@@ -490,8 +555,6 @@ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc)
snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
&snd_cobalt_pcm_capture_ops);
- snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
sp->info_flags = 0;
sp->private_data = cobsc;
strscpy(sp->name, "cobalt", sizeof(sp->name));
@@ -516,8 +579,6 @@ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc)
snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_PLAYBACK,
&snd_cobalt_pcm_playback_ops);
- snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
sp->info_flags = 0;
sp->private_data = cobsc;
strscpy(sp->name, "cobalt", sizeof(sp->name));
diff --git b/drivers/media/pci/cx18/cx18-alsa-pcm.c a/drivers/media/pci/cx18/cx18-alsa-pcm.c
index bed28b4b41f7..13f858c41836 100644
--- b/drivers/media/pci/cx18/cx18-alsa-pcm.c
+++ a/drivers/media/pci/cx18/cx18-alsa-pcm.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/vmalloc.h>
#include <media/v4l2-device.h>
@@ -200,6 +201,67 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ int ret;
+
+ snd_cx18_lock(cxsc);
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ snd_cx18_unlock(cxsc);
+ return ret;
+}
+
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ dprintk("%s called\n", __func__);
+
+ return snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ unsigned long flags;
+ unsigned char *dma_area = NULL;
+
+ spin_lock_irqsave(&cxsc->slock, flags);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing pcm capture region\n");
+ dma_area = substream->runtime->dma_area;
+ substream->runtime->dma_area = NULL;
+ }
+ spin_unlock_irqrestore(&cxsc->slock, flags);
+ vfree(dma_area);
+
+ return 0;
+}
+
static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
@@ -229,12 +291,24 @@ snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream)
return hwptr_done;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
static const struct snd_pcm_ops snd_cx18_pcm_capture_ops = {
.open = snd_cx18_pcm_capture_open,
.close = snd_cx18_pcm_capture_close,
+ .ioctl = snd_cx18_pcm_ioctl,
+ .hw_params = snd_cx18_pcm_hw_params,
+ .hw_free = snd_cx18_pcm_hw_free,
.prepare = snd_cx18_pcm_prepare,
.trigger = snd_cx18_pcm_trigger,
.pointer = snd_cx18_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
int snd_cx18_pcm_create(struct snd_cx18_card *cxsc)
@@ -260,7 +334,6 @@ int snd_cx18_pcm_create(struct snd_cx18_card *cxsc)
snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
&snd_cx18_pcm_capture_ops);
- snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
sp->info_flags = 0;
sp->private_data = cxsc;
strscpy(sp->name, cx->card_name, sizeof(sp->name));
diff --git b/drivers/media/pci/cx23885/cx23885-alsa.c a/drivers/media/pci/cx23885/cx23885-alsa.c
index df44ed7393a0..a8e980c6dacb 100644
--- b/drivers/media/pci/cx23885/cx23885-alsa.c
+++ a/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -495,6 +495,7 @@ static struct page *snd_cx23885_page(struct snd_pcm_substream *substream,
static const struct snd_pcm_ops snd_cx23885_pcm_ops = {
.open = snd_cx23885_pcm_open,
.close = snd_cx23885_close,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_cx23885_hw_params,
.hw_free = snd_cx23885_hw_free,
.prepare = snd_cx23885_prepare,
diff --git b/drivers/media/pci/cx25821/cx25821-alsa.c a/drivers/media/pci/cx25821/cx25821-alsa.c
index 301616426d8a..c2f2d7c782c7 100644
--- b/drivers/media/pci/cx25821/cx25821-alsa.c
+++ a/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -639,6 +639,7 @@ static struct page *snd_cx25821_page(struct snd_pcm_substream *substream,
static const struct snd_pcm_ops snd_cx25821_pcm_ops = {
.open = snd_cx25821_pcm_open,
.close = snd_cx25821_close,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_cx25821_hw_params,
.hw_free = snd_cx25821_hw_free,
.prepare = snd_cx25821_prepare,
diff --git b/drivers/media/pci/cx88/cx88-alsa.c a/drivers/media/pci/cx88/cx88-alsa.c
index 7d7aceecc985..e1e71ae293ed 100644
--- b/drivers/media/pci/cx88/cx88-alsa.c
+++ a/drivers/media/pci/cx88/cx88-alsa.c
@@ -585,6 +585,7 @@ static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
static const struct snd_pcm_ops snd_cx88_pcm_ops = {
.open = snd_cx88_pcm_open,
.close = snd_cx88_close,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_cx88_hw_params,
.hw_free = snd_cx88_hw_free,
.prepare = snd_cx88_prepare,
diff --git b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index 8f346d7da9c8..9e6019a159f4 100644
--- b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -16,6 +16,8 @@
#include "ivtv-alsa.h"
#include "ivtv-alsa-pcm.h"
+#include <linux/vmalloc.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
@@ -204,6 +206,67 @@ static int snd_ivtv_pcm_capture_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_ivtv_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
+ int ret;
+
+ snd_ivtv_lock(itvsc);
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ snd_ivtv_unlock(itvsc);
+ return ret;
+}
+
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
+static int snd_ivtv_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ dprintk("%s called\n", __func__);
+
+ return snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int snd_ivtv_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
+ unsigned long flags;
+ unsigned char *dma_area = NULL;
+
+ spin_lock_irqsave(&itvsc->slock, flags);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing pcm capture region\n");
+ dma_area = substream->runtime->dma_area;
+ substream->runtime->dma_area = NULL;
+ }
+ spin_unlock_irqrestore(&itvsc->slock, flags);
+ vfree(dma_area);
+
+ return 0;
+}
+
static int snd_ivtv_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
@@ -233,12 +296,24 @@ snd_pcm_uframes_t snd_ivtv_pcm_pointer(struct snd_pcm_substream *substream)
return hwptr_done;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
static const struct snd_pcm_ops snd_ivtv_pcm_capture_ops = {
.open = snd_ivtv_pcm_capture_open,
.close = snd_ivtv_pcm_capture_close,
+ .ioctl = snd_ivtv_pcm_ioctl,
+ .hw_params = snd_ivtv_pcm_hw_params,
+ .hw_free = snd_ivtv_pcm_hw_free,
.prepare = snd_ivtv_pcm_prepare,
.trigger = snd_ivtv_pcm_trigger,
.pointer = snd_ivtv_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc)
@@ -264,7 +339,6 @@ int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc)
snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
&snd_ivtv_pcm_capture_ops);
- snd_pcm_set_managed_buffer_all(sp, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
sp->info_flags = 0;
sp->private_data = itvsc;
strscpy(sp->name, itv->card_name, sizeof(sp->name));
diff --git b/drivers/media/pci/saa7134/saa7134-alsa.c a/drivers/media/pci/saa7134/saa7134-alsa.c
index 544ca57eee75..0385127dd7ff 100644
--- b/drivers/media/pci/saa7134/saa7134-alsa.c
+++ a/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -865,6 +865,7 @@ static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream,
static const struct snd_pcm_ops snd_card_saa7134_capture_ops = {
.open = snd_card_saa7134_capture_open,
.close = snd_card_saa7134_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_card_saa7134_hw_params,
.hw_free = snd_card_saa7134_hw_free,
.prepare = snd_card_saa7134_capture_prepare,
diff --git b/drivers/media/pci/solo6x10/solo6x10-g723.c a/drivers/media/pci/solo6x10/solo6x10-g723.c
index d6d16e8fd997..eaa57d835ea8 100644
--- b/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ a/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -97,6 +97,17 @@ void solo_g723_isr(struct solo_dev *solo_dev)
}
}
+static int snd_solo_hw_params(struct snd_pcm_substream *ss,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int snd_solo_hw_free(struct snd_pcm_substream *ss)
+{
+ return snd_pcm_lib_free_pages(ss);
+}
+
static const struct snd_pcm_hardware snd_solo_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
@@ -259,6 +270,9 @@ static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel,
static const struct snd_pcm_ops snd_solo_pcm_ops = {
.open = snd_solo_pcm_open,
.close = snd_solo_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_solo_hw_params,
+ .hw_free = snd_solo_hw_free,
.prepare = snd_solo_pcm_prepare,
.trigger = snd_solo_pcm_trigger,
.pointer = snd_solo_pcm_pointer,
@@ -337,11 +351,11 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev)
ss; ss = ss->next, i++)
sprintf(ss->name, "Camera #%d Audio", i);
- snd_pcm_set_managed_buffer_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- NULL,
- G723_PERIOD_BYTES * PERIODS,
- G723_PERIOD_BYTES * PERIODS);
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ NULL,
+ G723_PERIOD_BYTES * PERIODS,
+ G723_PERIOD_BYTES * PERIODS);
solo_dev->snd_pcm = pcm;
diff --git b/drivers/media/pci/tw686x/tw686x-audio.c a/drivers/media/pci/tw686x/tw686x-audio.c
index 54144e23a487..7786e51d19ae 100644
--- b/drivers/media/pci/tw686x/tw686x-audio.c
+++ a/drivers/media/pci/tw686x/tw686x-audio.c
@@ -78,6 +78,17 @@ void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
}
}
+static int tw686x_pcm_hw_params(struct snd_pcm_substream *ss,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss)
+{
+ return snd_pcm_lib_free_pages(ss);
+}
+
/*
* Audio parameters are global and shared among all
* capture channels. The driver prevents changes to
@@ -258,6 +269,9 @@ static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss)
static const struct snd_pcm_ops tw686x_pcm_ops = {
.open = tw686x_pcm_open,
.close = tw686x_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = tw686x_pcm_hw_params,
+ .hw_free = tw686x_pcm_hw_free,
.prepare = tw686x_pcm_prepare,
.trigger = tw686x_pcm_trigger,
.pointer = tw686x_pcm_pointer,
@@ -284,7 +298,7 @@ static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
ss; ss = ss->next, i++)
snprintf(ss->name, sizeof(ss->name), "vch%u audio", i);
- snd_pcm_set_managed_buffer_all(pcm,
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
&dev->pci_dev->dev,
TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
diff --git b/drivers/media/usb/cx231xx/cx231xx-audio.c a/drivers/media/usb/cx231xx/cx231xx-audio.c
index de42db6f6ad1..fd6e2df3d1b7 100644
--- b/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ a/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/soundcard.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -371,6 +372,28 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
return errCode;
}
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct snd_pcm_runtime *runtime = subs->runtime;
+ struct cx231xx *dev = snd_pcm_substream_chip(subs);
+
+ dev_dbg(dev->dev, "Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
static const struct snd_pcm_hardware snd_cx231xx_hw_capture = {
.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -461,6 +484,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
}
dev->adev.users--;
+ if (substream->runtime->dma_area) {
+ dev_dbg(dev->dev, "freeing\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
mutex_unlock(&dev->lock);
if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
@@ -476,6 +504,44 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+ int ret;
+
+ dev_dbg(dev->dev, "Setting capture parameters\n");
+
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+#if 0
+ /* TODO: set up cx231xx audio chip to deliver the correct audio format,
+ current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono */
+ unsigned int channels, rate, format;
+
+ format = params_format(hw_params);
+ rate = params_rate(hw_params);
+ channels = params_channels(hw_params);
+#endif
+
+ return ret;
+}
+
+static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+ dev_dbg(dev->dev, "Stop capture, if needed\n");
+
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
+
+ return 0;
+}
+
static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
@@ -548,12 +614,24 @@ static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
return hwptr_done;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
static const struct snd_pcm_ops snd_cx231xx_pcm_capture = {
.open = snd_cx231xx_capture_open,
.close = snd_cx231xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx231xx_hw_capture_params,
+ .hw_free = snd_cx231xx_hw_capture_free,
.prepare = snd_cx231xx_prepare,
.trigger = snd_cx231xx_capture_trigger,
.pointer = snd_cx231xx_capture_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
static int cx231xx_audio_init(struct cx231xx *dev)
@@ -588,7 +666,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_cx231xx_pcm_capture);
- snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
pcm->info_flags = 0;
pcm->private_data = dev;
strscpy(pcm->name, "Conexant cx231xx Capture", sizeof(pcm->name));
diff --git b/drivers/media/usb/em28xx/em28xx-audio.c a/drivers/media/usb/em28xx/em28xx-audio.c
index 6833b5bfe293..79dfbb25714b 100644
--- b/drivers/media/usb/em28xx/em28xx-audio.c
+++ a/drivers/media/usb/em28xx/em28xx-audio.c
@@ -30,6 +30,7 @@
#include <linux/spinlock.h>
#include <linux/soundcard.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -191,6 +192,28 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
return 0;
}
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+ size_t size)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(subs);
+ struct snd_pcm_runtime *runtime = subs->runtime;
+
+ dprintk("Allocating vbuffer\n");
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes > size)
+ return 0;
+
+ vfree(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc(size);
+ if (!runtime->dma_area)
+ return -ENOMEM;
+
+ runtime->dma_bytes = size;
+
+ return 0;
+}
+
static const struct snd_pcm_hardware snd_em28xx_hw_capture = {
.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
@@ -318,12 +341,63 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
}
em28xx_audio_analog_set(dev);
+ if (substream->runtime->dma_area) {
+ dprintk("freeing\n");
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ }
mutex_unlock(&dev->lock);
kref_put(&dev->ref, em28xx_free_device);
return 0;
}
+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int ret;
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ if (dev->disconnected)
+ return -ENODEV;
+
+ dprintk("Setting capture parameters\n");
+
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0)
+ return ret;
+#if 0
+ /*
+ * TODO: set up em28xx audio chip to deliver the correct audio format,
+ * current default is 48000hz multiplexed => 96000hz mono
+ * which shouldn't matter since analogue TV only supports mono
+ */
+ unsigned int channels, rate, format;
+
+ format = params_format(hw_params);
+ rate = params_rate(hw_params);
+ channels = params_channels(hw_params);
+#endif
+
+ return 0;
+}
+
+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+ struct em28xx_audio *adev = &dev->adev;
+
+ dprintk("Stop capture, if needed\n");
+
+ if (atomic_read(&adev->stream_started) > 0) {
+ atomic_set(&adev->stream_started, 0);
+ schedule_work(&adev->wq_trigger);
+ }
+
+ return 0;
+}
+
static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
@@ -397,6 +471,14 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
return hwptr_done;
}
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
/*
* AC97 volume control support
*/
@@ -626,9 +708,13 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
static const struct snd_pcm_ops snd_em28xx_pcm_capture = {
.open = snd_em28xx_capture_open,
.close = snd_em28xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_em28xx_hw_capture_params,
+ .hw_free = snd_em28xx_hw_capture_free,
.prepare = snd_em28xx_prepare,
.trigger = snd_em28xx_capture_trigger,
.pointer = snd_em28xx_capture_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
static void em28xx_audio_free_urb(struct em28xx *dev)
@@ -850,7 +936,6 @@ static int em28xx_audio_init(struct em28xx *dev)
goto card_free;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
- snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
pcm->info_flags = 0;
pcm->private_data = dev;
strscpy(pcm->name, "Empia 28xx Capture", sizeof(pcm->name));
diff --git b/drivers/media/usb/go7007/snd-go7007.c a/drivers/media/usb/go7007/snd-go7007.c
index ae27e988e578..b05fa227ffb2 100644
--- b/drivers/media/usb/go7007/snd-go7007.c
+++ a/drivers/media/usb/go7007/snd-go7007.c
@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/sched.h>
+#include <linux/vmalloc.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/i2c.h>
@@ -99,7 +100,16 @@ static int go7007_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct go7007 *go = snd_pcm_substream_chip(substream);
-
+ unsigned int bytes;
+
+ bytes = params_buffer_bytes(hw_params);
+ if (substream->runtime->dma_bytes > 0)
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_bytes = 0;
+ substream->runtime->dma_area = vmalloc(bytes);
+ if (substream->runtime->dma_area == NULL)
+ return -ENOMEM;
+ substream->runtime->dma_bytes = bytes;
go->audio_deliver = parse_audio_stream_data;
return 0;
}
@@ -109,6 +119,9 @@ static int go7007_snd_hw_free(struct snd_pcm_substream *substream)
struct go7007 *go = snd_pcm_substream_chip(substream);
go->audio_deliver = NULL;
+ if (substream->runtime->dma_bytes > 0)
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_bytes = 0;
return 0;
}
@@ -172,14 +185,22 @@ static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substr
return gosnd->hw_ptr;
}
+static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+
static const struct snd_pcm_ops go7007_snd_capture_ops = {
.open = go7007_snd_capture_open,
.close = go7007_snd_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = go7007_snd_hw_params,
.hw_free = go7007_snd_hw_free,
.prepare = go7007_snd_pcm_prepare,
.trigger = go7007_snd_pcm_trigger,
.pointer = go7007_snd_pcm_pointer,
+ .page = go7007_snd_pcm_page,
};
static int go7007_snd_free(struct snd_device *device)
@@ -239,8 +260,6 @@ int go7007_snd_init(struct go7007 *go)
gosnd->pcm->private_data = go;
snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE,
&go7007_snd_capture_ops);
- snd_pcm_set_managed_buffer_all(gosnd->pcm, SNDRV_DMA_TYPE_VMALLOC,
- NULL, 0, 0);
ret = snd_card_register(gosnd->card);
if (ret < 0) {
diff --git b/drivers/media/usb/usbtv/usbtv-audio.c a/drivers/media/usb/usbtv/usbtv-audio.c
index b57e94fb1977..e746c8ddfc49 100644
--- b/drivers/media/usb/usbtv/usbtv-audio.c
+++ a/drivers/media/usb/usbtv/usbtv-audio.c
@@ -85,6 +85,30 @@ static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_usbtv_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int rv;
+ struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+ rv = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+
+ if (rv < 0) {
+ dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n",
+ rv);
+ return rv;
+ }
+
+ return 0;
+}
+
+static int snd_usbtv_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
{
struct usbtv *chip = snd_pcm_substream_chip(substream);
@@ -312,6 +336,9 @@ static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
static const struct snd_pcm_ops snd_usbtv_pcm_ops = {
.open = snd_usbtv_pcm_open,
.close = snd_usbtv_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_usbtv_hw_params,
+ .hw_free = snd_usbtv_hw_free,
.prepare = snd_usbtv_prepare,
.trigger = snd_usbtv_card_trigger,
.pointer = snd_usbtv_pointer,
@@ -350,7 +377,7 @@ int usbtv_audio_init(struct usbtv *usbtv)
pcm->private_data = usbtv;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
- snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
NULL, USBTV_AUDIO_BUFFER, USBTV_AUDIO_BUFFER);
rv = snd_card_register(card);