Merge branch 'topic/ctxfi-fix' into topic/ctxfi

This commit is contained in:
Takashi Iwai 2009-06-02 15:55:22 +02:00
commit bd05dbd3b2
9 changed files with 94 additions and 110 deletions

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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);