summary refs log tree commit diff
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-06-02 15:55:22 +0200
committerTakashi Iwai <tiwai@suse.de>2009-06-02 15:55:22 +0200
commitbd05dbd3b22612455283610b4e006ee3e421b13d (patch)
tree06868be09771d6908acd657b1a9f66b0fb209bce /sound/pci
parent67fbf880631bb4493ad8d23f25562abdf09dc01d (diff)
parentc76157d9286ed598c241c212aa5a3c6e5107bd82 (diff)
downloadlinux-bd05dbd3b22612455283610b4e006ee3e421b13d.tar.gz
Merge branch 'topic/ctxfi-fix' into topic/ctxfi
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/Kconfig1
-rw-r--r--sound/pci/ctxfi/ctatc.c35
-rw-r--r--sound/pci/ctxfi/ctatc.h5
-rw-r--r--sound/pci/ctxfi/cthw20k1.c16
-rw-r--r--sound/pci/ctxfi/cthw20k2.c17
-rw-r--r--sound/pci/ctxfi/ctmixer.c8
-rw-r--r--sound/pci/ctxfi/ctpcm.c25
-rw-r--r--sound/pci/ctxfi/ctvmem.c77
-rw-r--r--sound/pci/ctxfi/ctvmem.h16
9 files changed, 92 insertions, 108 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 2d7fef5df017..3a7640feaf92 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -277,7 +277,6 @@ config SND_CS5535AUDIO
 
 config SND_CTXFI
 	tristate "Creative Sound Blaster X-Fi"
-	depends on X86
 	select SND_PCM
 	help
 	  If you want to use soundcards based on Creative Sound Blastr X-Fi
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index ead104ea1e35..684947546d81 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -72,15 +72,15 @@ static struct {
 	[FRONT]		= { .create = ct_alsa_pcm_create,
 			    .destroy = NULL,
 			    .public_name = "Front/WaveIn"},
-	[REAR]		= { .create = ct_alsa_pcm_create,
+	[SURROUND]	= { .create = ct_alsa_pcm_create,
 			    .destroy = NULL,
-			    .public_name = "Rear"},
+			    .public_name = "Surround"},
 	[CLFE]		= { .create = ct_alsa_pcm_create,
 			    .destroy = NULL,
 			    .public_name = "Center/LFE"},
-	[SURROUND]	= { .create = ct_alsa_pcm_create,
+	[SIDE]		= { .create = ct_alsa_pcm_create,
 			    .destroy = NULL,
-			    .public_name = "Surround"},
+			    .public_name = "Side"},
 	[IEC958]	= { .create = ct_alsa_pcm_create,
 			    .destroy = NULL,
 			    .public_name = "IEC958 Non-audio"},
@@ -119,7 +119,6 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm);
 
 static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
-	unsigned long flags;
 	struct snd_pcm_runtime *runtime;
 	struct ct_vm *vm;
 
@@ -129,9 +128,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 	runtime = apcm->substream->runtime;
 	vm = atc->vm;
 
-	spin_lock_irqsave(&atc->vm_lock, flags);
-	apcm->vm_block = vm->map(vm, runtime->dma_area, runtime->dma_bytes);
-	spin_unlock_irqrestore(&atc->vm_lock, flags);
+	apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
 
 	if (NULL == apcm->vm_block)
 		return -ENOENT;
@@ -141,7 +138,6 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 
 static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
-	unsigned long flags;
 	struct ct_vm *vm;
 
 	if (NULL == apcm->vm_block)
@@ -149,9 +145,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 
 	vm = atc->vm;
 
-	spin_lock_irqsave(&atc->vm_lock, flags);
 	vm->unmap(vm, apcm->vm_block);
-	spin_unlock_irqrestore(&atc->vm_lock, flags);
 
 	apcm->vm_block = NULL;
 }
@@ -161,9 +155,7 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
 	struct ct_vm *vm;
 	void *kvirt_addr;
 	unsigned long phys_addr;
-	unsigned long flags;
 
-	spin_lock_irqsave(&atc->vm_lock, flags);
 	vm = atc->vm;
 	kvirt_addr = vm->get_ptp_virt(vm, index);
 	if (kvirt_addr == NULL)
@@ -171,8 +163,6 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
 	else
 		phys_addr = virt_to_phys(kvirt_addr);
 
-	spin_unlock_irqrestore(&atc->vm_lock, flags);
-
 	return phys_addr;
 }
 
@@ -180,16 +170,15 @@ static unsigned int convert_format(snd_pcm_format_t snd_format)
 {
 	switch (snd_format) {
 	case SNDRV_PCM_FORMAT_U8:
-	case SNDRV_PCM_FORMAT_S8:
 		return SRC_SF_U8;
 	case SNDRV_PCM_FORMAT_S16_LE:
-	case SNDRV_PCM_FORMAT_U16_LE:
 		return SRC_SF_S16;
 	case SNDRV_PCM_FORMAT_S24_3LE:
 		return SRC_SF_S24;
-	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S32_LE:
 		return SRC_SF_S32;
+	case SNDRV_PCM_FORMAT_FLOAT_LE:
+		return SRC_SF_F32;
 	default:
 		printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
 			snd_format);
@@ -264,6 +253,9 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 		return 0;
 	}
 
+	/* first release old resources */
+	atc->pcm_release_resources(atc, apcm);
+
 	/* Get SRC resource */
 	desc.multi = apcm->substream->runtime->channels;
 	desc.msr = atc->msr;
@@ -506,6 +498,9 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 	int n_srcimp = 0, n_amixer = 0, n_srcc = 0, n_sum = 0;
 	struct src_node_conf_t src_node_conf[2] = {{0} };
 
+	/* first release old resources */
+	atc->pcm_release_resources(atc, apcm);
+
 	/* The numbers of converting SRCs and SRCIMPs should be determined
 	 * by pitch value. */
 
@@ -777,6 +772,9 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
 	int n_amixer = apcm->substream->runtime->channels, i = 0;
 	unsigned int pitch = 0, rsr = atc->pll_rate;
 
+	/* first release old resources */
+	atc->pcm_release_resources(atc, apcm);
+
 	/* Get SRC resource */
 	desc.multi = apcm->substream->runtime->channels;
 	desc.msr = 1;
@@ -1562,7 +1560,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
 	atc_set_ops(atc);
 
 	spin_lock_init(&atc->atc_lock);
-	spin_lock_init(&atc->vm_lock);
 
 	/* Find card model */
 	err = atc_identify_card(atc);
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 286c993d461a..b86d12cd4a19 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -29,9 +29,9 @@
 
 enum CTALSADEVS {		/* Types of alsa devices */
 	FRONT,
-	REAR,
-	CLFE,
 	SURROUND,
+	CLFE,
+	SIDE,
 	IEC958,
 	MIXER,
 	NUM_CTALSADEVS		/* This should always be the last */
@@ -101,7 +101,6 @@ struct ct_atc {
 	unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
 
 	spinlock_t atc_lock;
-	spinlock_t vm_lock;
 
 	int (*pcm_playback_prepare)(struct ct_atc *atc,
 				    struct ct_atc_pcm *apcm);
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 44283bd7b2df..b7b8e6f41d0d 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1249,19 +1249,15 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
 	}
 
 	trnctl = 0x13;  /* 32-bit, 4k-size page */
-#if BITS_PER_LONG == 64
-	ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1);
-	ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1);
-	trnctl |= (1<<2);
-#elif BITS_PER_LONG == 32
-	ptp_phys_low = info->vm_pgt_phys & (~0UL);
-	ptp_phys_high = 0;
-#else
-#	error "Unknown BITS_PER_LONG!"
-#endif
+	ptp_phys_low = (u32)info->vm_pgt_phys;
+	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+	if (sizeof(void *) == 8) /* 64bit address */
+		trnctl |= (1 << 2);
+#if 0 /* Only 4k h/w pages for simplicitiy */
 #if PAGE_SIZE == 8192
 	trnctl |= (1<<5);
 #endif
+#endif
 	hw_write_20kx(hw, PTPALX, ptp_phys_low);
 	hw_write_20kx(hw, PTPAHX, ptp_phys_high);
 	hw_write_20kx(hw, TRNCTL, trnctl);
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 7c24c2ca96bd..349728765f2c 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1203,19 +1203,10 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info)
 	}
 
 	vmctl = 0x80000C0F;  /* 32-bit, 4k-size page */
-#if BITS_PER_LONG == 64
-	ptp_phys_low = info->vm_pgt_phys & ((1UL<<32)-1);
-	ptp_phys_high = (info->vm_pgt_phys>>32) & ((1UL<<32)-1);
-	vmctl |= (3<<8);
-#elif BITS_PER_LONG == 32
-	ptp_phys_low = info->vm_pgt_phys & (~0UL);
-	ptp_phys_high = 0;
-#else
-#	error "Unknown BITS_PER_LONG!"
-#endif
-#if PAGE_SIZE == 8192
-#	error "Don't support 8k-page!"
-#endif
+	ptp_phys_low = (u32)info->vm_pgt_phys;
+	ptp_phys_high = upper_32_bits(info->vm_pgt_phys);
+	if (sizeof(void *) == 8) /* 64bit address */
+		vmctl |= (3 << 8);
 	/* Write page table physical address to all PTPAL registers */
 	for (i = 0; i < 64; i++) {
 		hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low);
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index b7950768c3f8..177c46e248db 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -168,7 +168,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[MIXER_WAVES_P] = {
 		.ctl = 1,
-		.name = "Surround Playback Volume",
+		.name = "Side Playback Volume",
 	},
 	[MIXER_WAVEC_P] = {
 		.ctl = 1,
@@ -176,7 +176,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[MIXER_WAVER_P] = {
 		.ctl = 1,
-		.name = "Rear Playback Volume",
+		.name = "Surround Playback Volume",
 	},
 
 	[MIXER_PCM_C_S] = {
@@ -213,7 +213,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[MIXER_WAVES_P_S] = {
 		.ctl = 1,
-		.name = "Surround Playback Switch",
+		.name = "Side Playback Switch",
 	},
 	[MIXER_WAVEC_P_S] = {
 		.ctl = 1,
@@ -221,7 +221,7 @@ ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 	},
 	[MIXER_WAVER_P_S] = {
 		.ctl = 1,
-		.name = "Rear Playback Switch",
+		.name = "Surround Playback Switch",
 	},
 	[MIXER_DIGITAL_IO_S] = {
 		.ctl = 0,
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index a64cb0ed8759..52ddf19d83bb 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -26,12 +26,10 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = {
 				   SNDRV_PCM_INFO_MMAP_VALID |
 				   SNDRV_PCM_INFO_PAUSE),
 	.formats		= (SNDRV_PCM_FMTBIT_U8 |
-				   SNDRV_PCM_FMTBIT_S8 |
 				   SNDRV_PCM_FMTBIT_S16_LE |
-				   SNDRV_PCM_FMTBIT_U16_LE |
 				   SNDRV_PCM_FMTBIT_S24_3LE |
-				   SNDRV_PCM_FMTBIT_S24_LE |
-				   SNDRV_PCM_FMTBIT_S32_LE),
+				   SNDRV_PCM_FMTBIT_S32_LE |
+				   SNDRV_PCM_FMTBIT_FLOAT_LE),
 	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
 				   SNDRV_PCM_RATE_8000_192000),
 	.rate_min		= 8000,
@@ -52,8 +50,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
 				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				   SNDRV_PCM_INFO_MMAP_VALID |
 				   SNDRV_PCM_INFO_PAUSE),
-	.formats		= (SNDRV_PCM_FMTBIT_S16_LE |
-				   SNDRV_PCM_FMTBIT_U16_LE),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
 	.rates			= (SNDRV_PCM_RATE_48000 |
 				   SNDRV_PCM_RATE_44100 |
 				   SNDRV_PCM_RATE_32000),
@@ -77,12 +74,10 @@ static struct snd_pcm_hardware ct_pcm_capture_hw = {
 				   SNDRV_PCM_INFO_PAUSE |
 				   SNDRV_PCM_INFO_MMAP_VALID),
 	.formats		= (SNDRV_PCM_FMTBIT_U8 |
-				   SNDRV_PCM_FMTBIT_S8 |
 				   SNDRV_PCM_FMTBIT_S16_LE |
-				   SNDRV_PCM_FMTBIT_U16_LE |
 				   SNDRV_PCM_FMTBIT_S24_3LE |
-				   SNDRV_PCM_FMTBIT_S24_LE |
-				   SNDRV_PCM_FMTBIT_S32_LE),
+				   SNDRV_PCM_FMTBIT_S32_LE |
+				   SNDRV_PCM_FMTBIT_FLOAT_LE),
 	.rates			= (SNDRV_PCM_RATE_CONTINUOUS |
 				   SNDRV_PCM_RATE_8000_96000),
 	.rate_min		= 8000,
@@ -447,6 +442,7 @@ static struct snd_pcm_ops ct_pcm_playback_ops = {
 	.prepare	= ct_pcm_playback_prepare,
 	.trigger	= ct_pcm_playback_trigger,
 	.pointer	= ct_pcm_playback_pointer,
+	.page		= snd_pcm_sgbuf_ops_page,
 };
 
 /* PCM operators for capture */
@@ -459,6 +455,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {
 	.prepare	= ct_pcm_capture_prepare,
 	.trigger	= ct_pcm_capture_trigger,
 	.pointer	= ct_pcm_capture_pointer,
+	.page		= snd_pcm_sgbuf_ops_page,
 };
 
 /* Create ALSA pcm device */
@@ -469,12 +466,10 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
 	struct snd_pcm *pcm;
 	int err;
 	int playback_count, capture_count;
-	char name[128];
 
-	strncpy(name, device_name, sizeof(name));
 	playback_count = (IEC958 == device) ? 1 : 8;
 	capture_count = (FRONT == device) ? 1 : 0;
-	err = snd_pcm_new(atc->card, name, device,
+	err = snd_pcm_new(atc->card, "ctxfi", device,
 			  playback_count, capture_count, &pcm);
 	if (err < 0) {
 		printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
@@ -484,7 +479,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
 	pcm->private_data = atc;
 	pcm->info_flags = 0;
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-	strcpy(pcm->name, device_name);
+	strlcpy(pcm->name, device_name, sizeof(pcm->name));
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
 
@@ -492,7 +487,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
 		snd_pcm_set_ops(pcm,
 				SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
 
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 			snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
 	return 0;
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index cecf77e3ee86..b7f8e58ae07d 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -18,12 +18,11 @@
 #include "ctvmem.h"
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <asm/page.h>	/* for PAGE_SIZE macro definition */
 #include <linux/io.h>
-#include <asm/pgtable.h>
+#include <sound/pcm.h>
 
-#define CT_PTES_PER_PAGE (PAGE_SIZE / sizeof(void *))
-#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * PAGE_SIZE)
+#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *))
+#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE)
 
 /* *
  * Find or create vm block based on requested @size.
@@ -35,25 +34,34 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
 	struct ct_vm_block *block = NULL, *entry = NULL;
 	struct list_head *pos = NULL;
 
+	size = CT_PAGE_ALIGN(size);
+	if (size > vm->size) {
+		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
+				  "memory space available!\n");
+		return NULL;
+	}
+
+	mutex_lock(&vm->lock);
 	list_for_each(pos, &vm->unused) {
 		entry = list_entry(pos, struct ct_vm_block, list);
 		if (entry->size >= size)
 			break; /* found a block that is big enough */
 	}
 	if (pos == &vm->unused)
-		return NULL;
+		goto out;
 
 	if (entry->size == size) {
 		/* Move the vm node from unused list to used list directly */
 		list_del(&entry->list);
 		list_add(&entry->list, &vm->used);
 		vm->size -= size;
-		return entry;
+		block = entry;
+		goto out;
 	}
 
 	block = kzalloc(sizeof(*block), GFP_KERNEL);
 	if (NULL == block)
-		return NULL;
+		goto out;
 
 	block->addr = entry->addr;
 	block->size = size;
@@ -62,6 +70,8 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
 	entry->size -= size;
 	vm->size -= size;
 
+ out:
+	mutex_unlock(&vm->lock);
 	return block;
 }
 
@@ -70,6 +80,9 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
 	struct ct_vm_block *entry = NULL, *pre_ent = NULL;
 	struct list_head *pos = NULL, *pre = NULL;
 
+	block->size = CT_PAGE_ALIGN(block->size);
+
+	mutex_lock(&vm->lock);
 	list_del(&block->list);
 	vm->size += block->size;
 
@@ -106,61 +119,41 @@ static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block)
 		pos = pre;
 		pre = pos->prev;
 	}
+	mutex_unlock(&vm->lock);
 }
 
 /* Map host addr (kmalloced/vmalloced) to device logical addr. */
 static struct ct_vm_block *
-ct_vm_map(struct ct_vm *vm, void *host_addr, int size)
+ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size)
 {
-	struct ct_vm_block *block = NULL;
-	unsigned long pte_start;
-	unsigned long i;
-	unsigned long pages;
-	unsigned long start_phys;
+	struct ct_vm_block *block;
+	unsigned int pte_start;
+	unsigned i, pages;
 	unsigned long *ptp;
 
-	/* do mapping */
-	if ((unsigned long)host_addr >= VMALLOC_START) {
-		printk(KERN_ERR "ctxfi: "
-		       "Fail! Not support vmalloced addr now!\n");
-		return NULL;
-	}
-
-	if (size > vm->size) {
-		printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
-				  "memory space available!\n");
-		return NULL;
-	}
-
-	start_phys = (virt_to_phys(host_addr) & PAGE_MASK);
-	pages = (PAGE_ALIGN(virt_to_phys(host_addr) + size)
-			- start_phys) >> PAGE_SHIFT;
-
-	ptp = vm->ptp[0];
-
-	block = get_vm_block(vm, (pages << PAGE_SHIFT));
+	block = get_vm_block(vm, size);
 	if (block == NULL) {
 		printk(KERN_ERR "ctxfi: No virtual memory block that is big "
 				  "enough to allocate!\n");
 		return NULL;
 	}
 
-	pte_start = (block->addr >> PAGE_SHIFT);
-	for (i = 0; i < pages; i++)
-		ptp[pte_start+i] = start_phys + (i << PAGE_SHIFT);
+	ptp = vm->ptp[0];
+	pte_start = (block->addr >> CT_PAGE_SHIFT);
+	pages = block->size >> CT_PAGE_SHIFT;
+	for (i = 0; i < pages; i++) {
+		unsigned long addr;
+		addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT);
+		ptp[pte_start + i] = addr;
+	}
 
-	block->addr += (virt_to_phys(host_addr) & (~PAGE_MASK));
 	block->size = size;
-
 	return block;
 }
 
 static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block)
 {
 	/* do unmapping */
-	block->size = ((block->addr + block->size + PAGE_SIZE - 1)
-			& PAGE_MASK) - (block->addr & PAGE_MASK);
-	block->addr &= PAGE_MASK;
 	put_vm_block(vm, block);
 }
 
@@ -191,6 +184,8 @@ int ct_vm_create(struct ct_vm **rvm)
 	if (NULL == vm)
 		return -ENOMEM;
 
+	mutex_init(&vm->lock);
+
 	/* Allocate page table pages */
 	for (i = 0; i < CT_PTP_NUM; i++) {
 		vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL);
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h
index 4eb5bdd5cad4..01e4fd0386a3 100644
--- a/sound/pci/ctxfi/ctvmem.h
+++ b/sound/pci/ctxfi/ctvmem.h
@@ -20,24 +20,36 @@
 
 #define CT_PTP_NUM	1	/* num of device page table pages */
 
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/list.h>
 
+/* The chip can handle the page table of 4k pages
+ * (emu20k1 can handle even 8k pages, but we don't use it right now)
+ */
+#define CT_PAGE_SIZE	4096
+#define CT_PAGE_SHIFT	12
+#define CT_PAGE_MASK	(~(PAGE_SIZE - 1))
+#define CT_PAGE_ALIGN(addr)	ALIGN(addr, CT_PAGE_SIZE)
+
 struct ct_vm_block {
 	unsigned int addr;	/* starting logical addr of this block */
 	unsigned int size;	/* size of this device virtual mem block */
 	struct list_head list;
 };
 
+struct snd_pcm_substream;
+
 /* Virtual memory management object for card device */
 struct ct_vm {
 	void *ptp[CT_PTP_NUM];		/* Device page table pages */
 	unsigned int size;		/* Available addr space in bytes */
 	struct list_head unused;	/* List of unused blocks */
 	struct list_head used;		/* List of used blocks */
+	struct mutex lock;
 
 	/* Map host addr (kmalloced/vmalloced) to device logical addr. */
-	struct ct_vm_block *(*map)(struct ct_vm *, void *host_addr, int size);
+	struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *,
+				   int size);
 	/* Unmap device logical addr area. */
 	void (*unmap)(struct ct_vm *, struct ct_vm_block *block);
 	void *(*get_ptp_virt)(struct ct_vm *vm, int index);