forked from Minki/linux
Merge branch 'topic/ctxfi-fix' into topic/ctxfi
This commit is contained in:
commit
bd05dbd3b2
@ -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
|
||||
|
@ -72,15 +72,15 @@ static struct {
|
||||
[FRONT] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.public_name = "Front/WaveIn"},
|
||||
[REAR] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.public_name = "Rear"},
|
||||
[CLFE] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.public_name = "Center/LFE"},
|
||||
[SURROUND] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.public_name = "Surround"},
|
||||
[CLFE] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.public_name = "Center/LFE"},
|
||||
[SIDE] = { .create = ct_alsa_pcm_create,
|
||||
.destroy = NULL,
|
||||
.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);
|
||||
|
@ -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);
|
||||
|
@ -1249,18 +1249,14 @@ 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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user