* Emu10k1x driver
@ 2004-05-12 0:31 fmoraes74
2004-05-12 2:16 ` James Courtier-Dutton
2004-05-12 11:05 ` Takashi Iwai
0 siblings, 2 replies; 17+ messages in thread
From: fmoraes74 @ 2004-05-12 0:31 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 394 bytes --]
Here's the first pass at the driver. I've tested it mainly with XMMS with the ALSA output plugin.
alsaplayer didn't work, not sure why. I've also tested with the pcm test in alsa-lib which seems to be jumping, so that's another problem.
I've removed the joystick support for now, but the only reason I added it was because the intel8x0.c driver has joystick support in it.
Enjoy,
Francisco
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: emu10k1x.c --]
[-- Type: text/x-c, Size: 25060 bytes --]
/*
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
* Driver EMU10K1X chips
*
* BUGS:
* --
*
* TODO:
* --
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>");
MODULE_DESCRIPTION("EMU10K1X");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{Dell Creative Labs,SB Live!}");
// module parameters (see "Module Parameters")
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
// some definitions were borrowed from emu10k1 driver as they seem to be the same
/************************************************************************************************/
/* PCI function 0 registers, address = <val> + PCIBASE0 */
/************************************************************************************************/
#define PTR 0x00 /* Indexed register set pointer register */
/* NOTE: The CHANNELNUM and ADDRESS words can */
/* be modified independently of each other. */
#define DATA 0x04 /* Indexed register set data register */
#define IPR 0x08 /* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */
#define IPR_CH_0_LOOP 0x00000800 /* Channel 0 loop */
#define IPR_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
#define INTE 0x0c /* Interrupt enable register */
#define INTE_CH_0_LOOP 0x00000800 /* Channel 0 loop */
#define INTE_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
#define HCFG 0x14 /* Hardware config register */
#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
/* NOTE: This should generally never be used. */
#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */
/* Should be set to 1 when the EMU10K1 is */
/* completely initialized. */
#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */
#define SPCS0 0x42 /* SPDIF output Channel Status 0 register */
#define SPCS1 0x43 /* SPDIF output Channel Status 1 register */
#define SPCS2 0x44 /* SPDIF output Channel Status 2 register */
#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */
#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */
#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */
#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */
#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */
#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */
#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */
#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */
#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */
#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */
#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */
#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */
#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */
#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */
#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */
#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */
#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */
#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */
#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */
#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */
#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */
#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
#define chip_t emu10k1x_t
typedef struct snd_emu10k1x_voice emu10k1x_voice_t;
typedef struct snd_emu10k1x emu10k1x_t;
typedef struct snd_emu10k1x_pcm emu10k1x_pcm_t;
struct snd_emu10k1x_voice {
emu10k1x_t *emu;
int number;
int use;
void (*interrupt)(emu10k1x_t *emu, emu10k1x_voice_t *pvoice);
emu10k1x_pcm_t *epcm;
};
struct snd_emu10k1x_pcm {
emu10k1x_t *emu;
snd_pcm_substream_t *substream;
emu10k1x_voice_t *voice;
unsigned short running;
};
// definition of the chip-specific record
struct snd_emu10k1x {
snd_card_t *card;
struct pci_dev *pci;
unsigned long port;
struct resource *res_port;
int irq;
unsigned int revision; /* chip revision */
unsigned int serial; /* serial number */
unsigned short model; /* subsystem id */
spinlock_t emu_lock;
spinlock_t reg_lock;
spinlock_t voice_lock;
ac97_t *ac97;
snd_pcm_t *pcm;
emu10k1x_voice_t voices[3];
struct snd_dma_device dma_dev;
struct snd_dma_buffer buffer;
};
#define emu10k1x_t_magic 0xa15a4501
/* hardware definition */
static snd_pcm_hardware_t snd_emu10k1x_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = (32*1024),
.period_bytes_min = 64,
.period_bytes_max = (32*1024),
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
unsigned int snd_emu10k1x_ptr_read(emu10k1x_t * emu,
unsigned int reg,
unsigned int chn)
{
unsigned long flags;
unsigned int regptr, val;
regptr = (reg << 16) | chn;
spin_lock_irqsave(&emu->emu_lock, flags);
outl(regptr, emu->port + PTR);
val = inl(emu->port + DATA);
spin_unlock_irqrestore(&emu->emu_lock, flags);
return val;
}
void snd_emu10k1x_ptr_write(emu10k1x_t *emu,
unsigned int reg,
unsigned int chn,
unsigned int data)
{
unsigned int regptr;
unsigned long flags;
regptr = (reg << 16) | chn;
spin_lock_irqsave(&emu->emu_lock, flags);
outl(regptr, emu->port + PTR);
outl(data, emu->port + DATA);
spin_unlock_irqrestore(&emu->emu_lock, flags);
}
void snd_emu10k1x_intr_enable(emu10k1x_t *emu, unsigned int intrenb)
{
unsigned long flags;
unsigned int enable;
spin_lock_irqsave(&emu->emu_lock, flags);
enable = inl(emu->port + INTE) | intrenb;
outl(enable, emu->port + INTE);
spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static int voice_alloc(emu10k1x_t *emu, emu10k1x_voice_t **rvoice)
{
emu10k1x_voice_t *voice;
int idx;
*rvoice = NULL;
for (idx = 0; idx < 3; idx ++) {
voice = &emu->voices[idx];
if (voice->use)
continue;
voice->use = 1;
*rvoice = voice;
return 0;
}
return -ENOMEM;
}
int snd_emu10k1x_voice_alloc(emu10k1x_t *emu, emu10k1x_voice_t **rvoice)
{
unsigned long flags;
int result;
snd_assert(rvoice != NULL, return -EINVAL);
spin_lock_irqsave(&emu->voice_lock, flags);
result = voice_alloc(emu, rvoice);
spin_unlock_irqrestore(&emu->voice_lock, flags);
return result;
}
int snd_emu10k1x_voice_free(emu10k1x_t *emu, emu10k1x_voice_t *pvoice)
{
unsigned long flags;
snd_assert(pvoice != NULL, return -EINVAL);
spin_lock_irqsave(&emu->voice_lock, flags);
pvoice->interrupt = NULL;
pvoice->use = 0;
pvoice->epcm = NULL;
spin_unlock_irqrestore(&emu->voice_lock, flags);
return 0;
}
static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime)
{
emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return);
if (epcm)
snd_magic_kfree(epcm);
}
static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice)
{
emu10k1x_pcm_t *epcm;
if ((epcm = voice->epcm) == NULL)
return;
if (epcm->substream == NULL)
return;
#if 0
printk("IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
epcm->substream->runtime->hw->pointer(emu, epcm->substream),
snd_pcm_lib_period_bytes(epcm->substream),
snd_pcm_lib_buffer_bytes(epcm->substream));
#endif
snd_pcm_period_elapsed(epcm->substream);
}
/* open callback */
static int snd_emu10k1x_playback_open(snd_pcm_substream_t *substream)
{
emu10k1x_t *chip = snd_pcm_substream_chip(substream);
emu10k1x_pcm_t *epcm;
snd_pcm_runtime_t *runtime = substream->runtime;
epcm = snd_magic_kcalloc(emu10k1x_pcm_t, 0, GFP_KERNEL);
if (epcm == NULL)
return -ENOMEM;
epcm->emu = chip;
epcm->substream = substream;
runtime->private_data = epcm;
runtime->private_free = snd_emu10k1x_pcm_free_substream;
runtime->hw = snd_emu10k1x_playback_hw;
return 0;
}
/* close callback */
static int snd_emu10k1x_playback_close(snd_pcm_substream_t *substream)
{
return 0;
}
/* hw_params callback */
static int snd_emu10k1x_pcm_hw_params(snd_pcm_substream_t *substream,
snd_pcm_hw_params_t * hw_params)
{
int err;
snd_pcm_runtime_t *runtime = substream->runtime;
emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
if((err = snd_emu10k1x_voice_alloc(epcm->emu, &epcm->voice)) < 0) {
return err;
}
epcm->voice->interrupt = snd_emu10k1x_pcm_interrupt;
return snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
}
/* hw_free callback */
static int snd_emu10k1x_pcm_hw_free(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
emu10k1x_pcm_t *epcm;
if (runtime->private_data == NULL)
return 0;
epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
if (epcm->voice) {
snd_emu10k1x_voice_free(epcm->emu, epcm->voice);
epcm->voice = NULL;
}
return snd_pcm_lib_free_pages(substream);
}
/* prepare callback */
static int snd_emu10k1x_pcm_prepare(snd_pcm_substream_t *substream)
{
emu10k1x_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
unsigned long flags;
int voice = epcm->voice->number;
spin_lock_irqsave(&emu->reg_lock, flags);
snd_emu10k1x_ptr_write(emu, 0x00, voice, 0);
snd_emu10k1x_ptr_write(emu, 0x01, voice, 0);
snd_emu10k1x_ptr_write(emu, 0x02, voice, 0);
snd_emu10k1x_ptr_write(emu, 0x04, voice, runtime->dma_addr);
snd_emu10k1x_ptr_write(emu, 0x05, voice, 0x8000<<0x10); // buffer size
snd_emu10k1x_ptr_write(emu, 0x06, voice, 0);
snd_emu10k1x_ptr_write(emu, 0x07, voice, 0);
snd_emu10k1x_ptr_write(emu, 0x08, voice, 0);
spin_unlock_irqrestore(&emu->reg_lock, flags);
return 0;
}
/* trigger callback */
static int snd_emu10k1x_pcm_trigger(snd_pcm_substream_t *substream,
int cmd)
{
emu10k1x_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
unsigned long flags;
int channel = epcm->voice->number;
int result = 0;
// printk("trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream));
spin_lock_irqsave(&emu->reg_lock, flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_emu10k1x_ptr_write(emu, 0x40, 0, snd_emu10k1x_ptr_read(emu, 0x40, 0)|(1<<channel));
epcm->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
snd_emu10k1x_ptr_write(emu, 0x40, 0, snd_emu10k1x_ptr_read(emu, 0x40, 0) & ~(1<<channel));
epcm->running = 0;
break;
default:
result = -EINVAL;
break;
}
spin_unlock_irqrestore(&emu->reg_lock, flags);
return result;
}
/* pointer callback */
static snd_pcm_uframes_t
snd_emu10k1x_pcm_pointer(snd_pcm_substream_t *substream)
{
emu10k1x_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
unsigned int ptr = 0;
int channel = epcm->voice->number;
if (!epcm->running)
return 0;
// printk("pointer: %08X %08X\n",
// snd_emu10k1x_ptr_read(emu, 0x06, channel),
// snd_emu10k1x_ptr_read(emu, 0x12, channel));
ptr = bytes_to_frames(runtime, snd_emu10k1x_ptr_read(emu, 0x06, channel));
if (ptr >= runtime->buffer_size)
ptr -= runtime->buffer_size;
// printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits,
// (int)runtime->rate);
return ptr;
}
/* operators */
static snd_pcm_ops_t snd_emu10k1x_playback_ops = {
.open = snd_emu10k1x_playback_open,
.close = snd_emu10k1x_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_emu10k1x_pcm_hw_params,
.hw_free = snd_emu10k1x_pcm_hw_free,
.prepare = snd_emu10k1x_pcm_prepare,
.trigger = snd_emu10k1x_pcm_trigger,
.pointer = snd_emu10k1x_pcm_pointer,
};
static unsigned short snd_emu10k1x_ac97_read(ac97_t *ac97,
unsigned short reg)
{
emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, ac97->private_data, return -ENXIO);
unsigned long flags;
unsigned short val;
spin_lock_irqsave(&emu->emu_lock, flags);
outb(reg, emu->port + AC97ADDRESS);
val = inw(emu->port + AC97DATA);
spin_unlock_irqrestore(&emu->emu_lock, flags);
return val;
}
static void snd_emu10k1x_ac97_write(ac97_t *ac97,
unsigned short reg, unsigned short val)
{
emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, ac97->private_data, return);
unsigned long flags;
spin_lock_irqsave(&emu->emu_lock, flags);
outb(reg, emu->port + AC97ADDRESS);
outw(val, emu->port + AC97DATA);
spin_unlock_irqrestore(&emu->emu_lock, flags);
}
static int snd_emu10k1x_ac97(emu10k1x_t *chip)
{
ac97_bus_t bus, *pbus;
ac97_t ac97;
int err;
memset(&bus, 0, sizeof(bus));
bus.write = snd_emu10k1x_ac97_write;
bus.read = snd_emu10k1x_ac97_read;
if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
}
static int snd_emu10k1x_free(emu10k1x_t *chip)
{
snd_emu10k1x_ptr_write(chip, 0x40, 0, 0);
// disable interrupts
outl(0, chip->port + INTE);
// disable audio
outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
// release the i/o port
if (chip->res_port) {
release_resource(chip->res_port);
kfree_nocheck(chip->res_port);
}
// release the irq
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
// release the data
snd_magic_kfree(chip);
return 0;
}
static int snd_emu10k1x_dev_free(snd_device_t *device)
{
emu10k1x_t *chip = snd_magic_cast(emu10k1x_t,
device->device_data, return -ENXIO);
return snd_emu10k1x_free(chip);
}
static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
unsigned int status;
emu10k1x_t *chip = snd_magic_cast(emu10k1x_t, dev_id, return);
int i;
int mask;
spin_lock(&chip->emu_lock);
status = inl(chip->port + IPR);
// call updater, unlock before it
spin_unlock(&chip->emu_lock);
mask = IPR_CH_0_LOOP;
for(i = 0; i < 3; i++) {
emu10k1x_voice_t *pvoice = chip->voices;
if(status & mask) {
if(pvoice->use && pvoice->interrupt)
pvoice->interrupt(chip, pvoice);
}
pvoice++;
mask <<= 1;
}
spin_lock(&chip->emu_lock);
// acknowledge the interrupt if necessary
outl(status, chip->port+IPR);
spin_unlock(&chip->emu_lock);
// printk(KERN_INFO "interrupt %08x\n", status);
return IRQ_HANDLED;
}
static void snd_emu10k1x_pcm_free(snd_pcm_t *pcm)
{
emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, pcm->private_data, return);
emu->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int __devinit snd_emu10k1x_pcm(emu10k1x_t *emu, int device, snd_pcm_t **rpcm)
{
snd_pcm_t *pcm;
snd_pcm_substream_t *substream;
int err;
if (rpcm)
*rpcm = NULL;
if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 1, 0, &pcm)) < 0)
return err;
pcm->private_data = emu;
pcm->private_free = snd_emu10k1x_pcm_free;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops);
// snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1x_capture_ops);
pcm->info_flags = 0;
pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
strcpy(pcm->name, "EMU10K1X");
emu->pcm = pcm;
for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
substream;
substream = substream->next)
if ((err = snd_pcm_lib_preallocate_pages(substream,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
32*1024, 32*1024)) < 0)
return err;
/*
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
substream;
substream = substream->next)
snd_pcm_lib_preallocate_pages(substream,
SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(emu->pci),
64*1024, 64*1024);
*/
if (rpcm)
*rpcm = pcm;
return 0;
}
static int __devinit snd_emu10k1x_create(snd_card_t *card,
struct pci_dev *pci,
emu10k1x_t **rchip)
{
emu10k1x_t *chip;
int err;
int ch;
static snd_device_ops_t ops = {
.dev_free = snd_emu10k1x_dev_free,
};
*rchip = NULL;
if ((err = pci_enable_device(pci)) < 0)
return err;
if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
printk(KERN_ERR "error to set 28bit mask DMA\n");
return -ENXIO;
}
chip = snd_magic_kcalloc(emu10k1x_t, 0, GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->card = card;
chip->pci = pci;
chip->irq = -1;
spin_lock_init(&emu->emu_lock);
spin_lock_init(&emu->reg_lock);
spin_lock_init(&emu->voice_lock);
chip->port = pci_resource_start(pci, 0);
if ((chip->res_port = request_region(chip->port, 8,
"My Chip")) == NULL) {
snd_emu10k1x_free(chip);
printk(KERN_ERR "cannot allocate the port\n");
return -EBUSY;
}
if (request_irq(pci->irq, snd_emu10k1x_interrupt,
SA_INTERRUPT|SA_SHIRQ, "EMU10K1X",
(void *)chip)) {
snd_emu10k1x_free(chip);
printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
chip->dma_dev.dev = snd_dma_pci_data(pci);
if(snd_dma_alloc_pages(&chip->dma_dev, 32 * 1024, &chip->buffer) < 0) {
snd_emu10k1x_free(chip);
return -ENOMEM;
}
pci_set_master(pci);
/* read revision & serial */
pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision);
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
chip->revision, chip->serial);
outl(0, chip->port + INTE);
for(ch = 0; ch < 3; ch++) {
chip->voices[ch].emu = chip;
chip->voices[ch].number = ch;
}
/*
* Init to 0x02109204 :
* Clock accuracy = 0 (1000ppm)
* Sample Rate = 2 (48kHz)
* Audio Channel = 1 (Left of 2)
* Source Number = 0 (Unspecified)
* Generation Status = 1 (Original for Cat Code 12)
* Cat Code = 12 (Digital Signal Mixer)
* Mode = 0 (Mode 0)
* Emphasis = 0 (None)
* CP = 1 (Copyright unasserted)
* AN = 0 (Audio data)
* P = 0 (Consumer)
*/
snd_emu10k1x_ptr_write(chip, SPCS0, 0,
SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
snd_emu10k1x_ptr_write(chip, SPCS1, 0,
SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
snd_emu10k1x_ptr_write(chip, SPCS2, 0,
SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
SPCS_GENERATIONSTATUS | 0x00001200 |
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f); // ???
snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG);
snd_emu10k1x_intr_enable(chip, INTE_CH_0_LOOP);
snd_emu10k1x_intr_enable(chip, INTE_CH_0_LOOP<<1);
snd_emu10k1x_intr_enable(chip, INTE_CH_0_LOOP<<2);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
chip, &ops)) < 0) {
snd_emu10k1x_free(chip);
return err;
}
*rchip = chip;
return 0;
}
static void snd_emu10k1x_proc_reg_read(snd_info_entry_t *entry,
snd_info_buffer_t * buffer)
{
emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, entry->private_data, return);
snd_iprintf(buffer, "Registers:\n\n");
unsigned long value,value1,value2;
unsigned long flags;
int i;
for(i = 0; i < 0x40; i+=4) {
spin_lock_irqsave(&emu->emu_lock, flags);
value = inl(emu->port + i);
spin_unlock_irqrestore(&emu->emu_lock, flags);
snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
}
snd_iprintf(buffer, "\nRegisters\n\n");
for(i = 0; i < 0x50; i++) {
value = snd_emu10k1x_ptr_read(emu, i, 0);
value1 = snd_emu10k1x_ptr_read(emu, i, 1);
value2 = snd_emu10k1x_ptr_read(emu, i, 2);
snd_iprintf(buffer, "%02X: %08lX %08lX %08lX\n", i, value, value, value2);
}
}
int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu)
{
snd_info_entry_t *entry;
if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry))
snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read);
return 0;
}
static int __devinit snd_emu10k1x_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
snd_card_t *card;
emu10k1x_t *chip;
int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
return -ENOENT;
}
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
}
if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) {
snd_card_free(card);
return err;
}
if ((err = snd_emu10k1x_ac97(chip)) < 0) {
snd_card_free(card);
return err;
}
snd_emu10k1x_proc_init(chip);
strcpy(card->driver, "Dell SB Live");
strcpy(card->shortname, "EMU10K1X");
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->port, chip->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
pci_set_drvdata(pci, card);
dev++;
return 0;
}
static void __devexit snd_emu10k1x_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
// PCI IDs
static struct pci_device_id snd_emu10k1x_ids[] = {
{ 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
// pci_driver definition
static struct pci_driver driver = {
.name = "Emu10k1x",
.id_table = snd_emu10k1x_ids,
.probe = snd_emu10k1x_probe,
.remove = __devexit_p(snd_emu10k1x_remove),
};
// initialization of the module
static int __init alsa_card_emu10k1x_init(void)
{
int err;
if ((err = pci_module_init(&driver)) > 0) {
#ifdef MODULE
printk(KERN_ERR "EMU10K1X soundcard not found or device busy\n");
#endif
return err;
}
return 0;
}
// clean up the module
static void __exit alsa_card_emu10k1x_exit(void)
{
pci_unregister_driver(&driver);
}
module_init(alsa_card_emu10k1x_init)
module_exit(alsa_card_emu10k1x_exit)
EXPORT_NO_SYMBOLS; /* for old kernels only */
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-12 0:31 Emu10k1x driver fmoraes74
@ 2004-05-12 2:16 ` James Courtier-Dutton
2004-05-12 2:46 ` Francisco Moraes
2004-05-14 16:55 ` Takashi Iwai
2004-05-12 11:05 ` Takashi Iwai
1 sibling, 2 replies; 17+ messages in thread
From: James Courtier-Dutton @ 2004-05-12 2:16 UTC (permalink / raw)
To: alsa-devel
fmoraes74@netzero.net wrote:
> Here's the first pass at the driver. I've tested it mainly with XMMS with the ALSA output plugin.
>
> alsaplayer didn't work, not sure why. I've also tested with the pcm test in alsa-lib which seems to be jumping, so that's another problem.
>
> I've removed the joystick support for now, but the only reason I added it was because the intel8x0.c driver has joystick support in it.
>
> Enjoy,
>
> Francisco
>
>
I would like to add some information that might help people modifying
this for the Audigy LS.
The outputs for the card work in 2 modes.
1) Probably analogue on the output jacks.
snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f);
snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
2) Probably digital spdif on the output jacks.
snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x1000f);
snd_emu10k1x_ptr_write(chip, 0x45, 0, 0x700);
To enable this driver loading for the Audigy LS, have the following PCI IDs.
static struct pci_device_id snd_emu10k1x_ids[] = {
{ 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM
version (EMU10K1X) */
{ 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS */
{ 0, }
};
Other information: -
value = snd_emu10k1x_ptr_read(chip, 0x74, 0);
printk("Some special chip ID = %04x\n",value);
Further additions to the snd_emu10k1x_create() function, after the lines
snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f); // ???
snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
snd_emu10k1x_ptr_write(chip, 0x65, 0, 0x1000);
snd_emu10k1x_ptr_write(chip, 0x72, 0, 0xf0f003f);
snd_emu10k1x_ptr_write(chip, 0x71, 0, 0xf0000000);
snd_emu10k1x_ptr_write(chip, 0x61, 0, 0x0);
snd_emu10k1x_ptr_write(chip, 0x62, 0, 0x0);
The AudigyLS also seems to use the emu10k1x_ptr 0x75 a lot in interrupt
routines, but the Dell OEM one does not.
Cheers
James
-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to deliver
higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-12 2:16 ` James Courtier-Dutton
@ 2004-05-12 2:46 ` Francisco Moraes
2004-05-14 16:55 ` Takashi Iwai
1 sibling, 0 replies; 17+ messages in thread
From: Francisco Moraes @ 2004-05-12 2:46 UTC (permalink / raw)
To: alsa-devel
I'd like to send special thanks for James Courtier-Dutton and Takashi
Iwai for helping out with some of the questions I had during the driver.
The frames concept took me a while and also the problem that I had
initally of mismatched buffer size and sample rate.
Francisco
-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to deliver
higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-12 2:16 ` James Courtier-Dutton
2004-05-12 2:46 ` Francisco Moraes
@ 2004-05-14 16:55 ` Takashi Iwai
2004-05-14 17:14 ` James Courtier-Dutton
1 sibling, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2004-05-14 16:55 UTC (permalink / raw)
To: James Courtier-Dutton; +Cc: Francisco Moraes, alsa-devel
At Wed, 12 May 2004 03:16:14 +0100,
James Courtier-Dutton wrote:
>
> fmoraes74@netzero.net wrote:
> > Here's the first pass at the driver. I've tested it mainly with XMMS with the ALSA output plugin.
> >
> > alsaplayer didn't work, not sure why. I've also tested with the pcm test in alsa-lib which seems to be jumping, so that's another problem.
> >
> > I've removed the joystick support for now, but the only reason I added it was because the intel8x0.c driver has joystick support in it.
> >
> > Enjoy,
> >
> > Francisco
> >
> >
>
> I would like to add some information that might help people modifying
> this for the Audigy LS.
>
> The outputs for the card work in 2 modes.
> 1) Probably analogue on the output jacks.
> snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f);
> snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
it's already in emu10k1x.c.
> 2) Probably digital spdif on the output jacks.
> snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x1000f);
> snd_emu10k1x_ptr_write(chip, 0x45, 0, 0x700);
it's not.
> To enable this driver loading for the Audigy LS, have the following PCI IDs.
> static struct pci_device_id snd_emu10k1x_ids[] = {
> { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM
> version (EMU10K1X) */
> { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS */
> { 0, }
> };
so, just adding the pci id for audigy LS would suffice at least for
analog output?
>
> Other information: -
> value = snd_emu10k1x_ptr_read(chip, 0x74, 0);
> printk("Some special chip ID = %04x\n",value);
what value on Dell OEM?
> Further additions to the snd_emu10k1x_create() function, after the lines
> snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f); // ???
> snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
hmm...
> snd_emu10k1x_ptr_write(chip, 0x65, 0, 0x1000);
> snd_emu10k1x_ptr_write(chip, 0x72, 0, 0xf0f003f);
routing?
> snd_emu10k1x_ptr_write(chip, 0x71, 0, 0xf0000000);
> snd_emu10k1x_ptr_write(chip, 0x61, 0, 0x0);
> snd_emu10k1x_ptr_write(chip, 0x62, 0, 0x0);
>
> The AudigyLS also seems to use the emu10k1x_ptr 0x75 a lot in interrupt
> routines, but the Dell OEM one does not.
what value is supposed to be on 0x75?
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-14 16:55 ` Takashi Iwai
@ 2004-05-14 17:14 ` James Courtier-Dutton
2004-05-14 17:32 ` Takashi Iwai
0 siblings, 1 reply; 17+ messages in thread
From: James Courtier-Dutton @ 2004-05-14 17:14 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
Takashi Iwai wrote:
> At Wed, 12 May 2004 03:16:14 +0100,
> James Courtier-Dutton wrote:
>
>>fmoraes74@netzero.net wrote:
>>
>>>Here's the first pass at the driver. I've tested it mainly with XMMS with the ALSA output plugin.
>>>
>>>alsaplayer didn't work, not sure why. I've also tested with the pcm test in alsa-lib which seems to be jumping, so that's another problem.
>>>
>>>I've removed the joystick support for now, but the only reason I added it was because the intel8x0.c driver has joystick support in it.
>>>
>>>Enjoy,
>>>
>>>Francisco
>>>
>>>
>>
>>I would like to add some information that might help people modifying
>>this for the Audigy LS.
>>
>>The outputs for the card work in 2 modes.
>>1) Probably analogue on the output jacks.
>>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f);
>>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
>
>
> it's already in emu10k1x.c.
>
>
>>2) Probably digital spdif on the output jacks.
>>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x1000f);
>>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0x700);
>
>
> it's not.
Those (1) and (2) should work on bother the LS and the Dell OEM.
>
>
>>To enable this driver loading for the Audigy LS, have the following PCI IDs.
>>static struct pci_device_id snd_emu10k1x_ids[] = {
>> { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM
>>version (EMU10K1X) */
>> { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS */
>> { 0, }
>>};
>
>
> so, just adding the pci id for audigy LS would suffice at least for
> analog output?
I don't think so, because of all the extra code that will be needed in
the interrupt routines.
>
>
>>Other information: -
>>value = snd_emu10k1x_ptr_read(chip, 0x74, 0);
>>printk("Some special chip ID = %04x\n",value);
>
>
> what value on Dell OEM?
I don't know. Might be worth trying it on the Audigy 2 as well.
>
>
>>Further additions to the snd_emu10k1x_create() function, after the lines
>>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f); // ???
>>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
>
>
> hmm...
>
>
>>snd_emu10k1x_ptr_write(chip, 0x65, 0, 0x1000);
>>snd_emu10k1x_ptr_write(chip, 0x72, 0, 0xf0f003f);
>
>
> routing?
>
>
>>snd_emu10k1x_ptr_write(chip, 0x71, 0, 0xf0000000);
>>snd_emu10k1x_ptr_write(chip, 0x61, 0, 0x0);
>>snd_emu10k1x_ptr_write(chip, 0x62, 0, 0x0);
>>
>>The AudigyLS also seems to use the emu10k1x_ptr 0x75 a lot in interrupt
>>routines, but the Dell OEM one does not.
>
>
> what value is supposed to be on 0x75?
I have no idea. But some trial and error with some actual hardware
should help.
>
>
> Takashi
>
>
Takashi,
I am waiting for someone to donate an Audigy LS to me. I will then be
able to build a driver for it.
It seems that the Audigy LS is quite a lot different from the Dell OEM,
so I will probably create a new .c file for it.
Maybe at a later stage, when everything works well, we might decide to
join the two drivers.
Also, if we get the Audigy LS working, it might shed some light on the
P16 or P17 chip details in the Audigy 2.
For features like high sample rates etc.
I have had one offer so far for an Audigy LS, so, if it arrives, I will
start work on it.
Cheers
James
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-14 17:14 ` James Courtier-Dutton
@ 2004-05-14 17:32 ` Takashi Iwai
2004-05-14 18:48 ` James Courtier-Dutton
0 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2004-05-14 17:32 UTC (permalink / raw)
To: James Courtier-Dutton; +Cc: alsa-devel
At Fri, 14 May 2004 18:14:47 +0100,
James Courtier-Dutton wrote:
>
> >>I would like to add some information that might help people modifying
> >>this for the Audigy LS.
> >>
> >>The outputs for the card work in 2 modes.
> >>1) Probably analogue on the output jacks.
> >>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f);
> >>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
> >
> >
> > it's already in emu10k1x.c.
> >
> >
> >>2) Probably digital spdif on the output jacks.
> >>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x1000f);
> >>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0x700);
> >
> >
> > it's not.
>
> Those (1) and (2) should work on bother the LS and the Dell OEM.
then, are they exclusive?
> >>To enable this driver loading for the Audigy LS, have the following PCI IDs.
> >>static struct pci_device_id snd_emu10k1x_ids[] = {
> >> { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM
> >>version (EMU10K1X) */
> >> { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS */
> >> { 0, }
> >>};
> >
> >
> > so, just adding the pci id for audigy LS would suffice at least for
> > analog output?
>
> I don't think so, because of all the extra code that will be needed in
> the interrupt routines.
ok...
(snip)
> Takashi,
>
> I am waiting for someone to donate an Audigy LS to me. I will then be
> able to build a driver for it.
> It seems that the Audigy LS is quite a lot different from the Dell OEM,
> so I will probably create a new .c file for it.
> Maybe at a later stage, when everything works well, we might decide to
> join the two drivers.
that's fine. meanwhile, emu10k1x.c is already on cvs.
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-14 17:32 ` Takashi Iwai
@ 2004-05-14 18:48 ` James Courtier-Dutton
0 siblings, 0 replies; 17+ messages in thread
From: James Courtier-Dutton @ 2004-05-14 18:48 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
Takashi Iwai wrote:
> At Fri, 14 May 2004 18:14:47 +0100,
> James Courtier-Dutton wrote:
>
>>>>I would like to add some information that might help people modifying
>>>>this for the Audigy LS.
>>>>
>>>>The outputs for the card work in 2 modes.
>>>>1) Probably analogue on the output jacks.
>>>>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f);
>>>>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
>>>
>>>>2) Probably digital spdif on the output jacks.
>>>>snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x1000f);
>>>>snd_emu10k1x_ptr_write(chip, 0x45, 0, 0x700);
>>>
>>Those (1) and (2) should work on bother the LS and the Dell OEM.
>
>
> then, are they exclusive?
>
>
I think you could add a mixer toggle switch for either (1) or (2).
I don't know what each bit in those registers does, so for now it could
probably be exclusive.
I have also heard that the way to program the Audigy LS might also apply
in some way the Audigy 2 to get the high samples rates working on the
Audigy 2.
Hopefully I will get certain answers soon.
Cheers
James
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-12 0:31 Emu10k1x driver fmoraes74
2004-05-12 2:16 ` James Courtier-Dutton
@ 2004-05-12 11:05 ` Takashi Iwai
1 sibling, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2004-05-12 11:05 UTC (permalink / raw)
To: fmoraes74; +Cc: alsa-devel
At Wed, 12 May 2004 00:31:43 GMT,
fmoraes74@netzero.net wrote:
>
> Here's the first pass at the driver. I've tested it mainly with XMMS with the ALSA output plugin.
nice, i'll add this to alsa-driver tree.
i guess pci/emu10k1 is the best location.
would you mind to change the indentation level to 8, as described in
Documentation/CodingStyle?
kernel people prefer to have the codes with the same style.
> alsaplayer didn't work, not sure why. I've also tested with the pcm
> test in alsa-lib which seems to be jumping, so that's another
> problem.
>
> I've removed the joystick support for now, but the only reason I
> added it was because the intel8x0.c driver has joystick support in
> it.
as i wrote in another mail, it's better to split it out of the sound
driver as long as it's possible.
thanks,
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to deliver
higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
@ 2004-05-12 18:36 fmoraes74
2004-05-13 13:17 ` Takashi Iwai
0 siblings, 1 reply; 17+ messages in thread
From: fmoraes74 @ 2004-05-12 18:36 UTC (permalink / raw)
To: tiwai; +Cc: fmoraes74, alsa-devel
> nice, i'll add this to alsa-driver tree.
> i guess pci/emu10k1 is the best location.
That's fine. I had it under pci on my system just because it was easier.
> would you mind to change the indentation level to 8, as described in
Documentation/CodingStyle?
> kernel people prefer to have the codes with the same style.
No problem but I won't be able to do that for a couple of days now. If someone wants to reformat the code, feel free to do it, as I haven't changed anything.
> alsaplayer didn't work, not sure why. I've also tested with the pcm
> test in alsa-lib which seems to be jumping, so that's another
> problem.
Any ideas/suggestions on the alsaplayer? I will test it more once I have time, but it bothered me that it didn't work with my driver.
Regards,
Francisco
________________________________________________________________
The best thing to hit the Internet in years - NetZero HiSpeed!
Surf the Web up to FIVE TIMES FASTER!
Only $14.95/ month -visit www.netzero.com to sign up today!
-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to deliver
higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-12 18:36 fmoraes74
@ 2004-05-13 13:17 ` Takashi Iwai
0 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2004-05-13 13:17 UTC (permalink / raw)
To: fmoraes74; +Cc: alsa-devel
At Wed, 12 May 2004 18:36:56 GMT,
fmoraes74@netzero.net wrote:
>
>
> > nice, i'll add this to alsa-driver tree.
> > i guess pci/emu10k1 is the best location.
>
> That's fine. I had it under pci on my system just because it was easier.
>
> > would you mind to change the indentation level to 8, as described in
> Documentation/CodingStyle?
> > kernel people prefer to have the codes with the same style.
>
> No problem but I won't be able to do that for a couple of days
> now. If someone wants to reformat the code, feel free to do it, as I
> haven't changed anything.
ok, i'll do it when i put this to cvs tree.
> > alsaplayer didn't work, not sure why. I've also tested with the pcm
> > test in alsa-lib which seems to be jumping, so that's another
> > problem.
>
> Any ideas/suggestions on the alsaplayer? I will test it more once I
> have time, but it bothered me that it didn't work with my driver.
what alsaplayer tells exactly? the configuration failure, or you hear
weird sounds?
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
[parent not found: <20040514.045055.28422.197543@webmail10.nyc.untd.com>]
* Re: Emu10k1x driver
[not found] <20040514.045055.28422.197543@webmail10.nyc.untd.com>
@ 2004-05-14 13:35 ` Takashi Iwai
2004-05-14 23:49 ` Francisco Moraes
0 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2004-05-14 13:35 UTC (permalink / raw)
To: fmoraes74; +Cc: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 753 bytes --]
At Fri, 14 May 2004 11:50:50 GMT,
fmoraes74@netzero.com wrote:
>
> Here's a revised version of the driver. I found a bug in the
> previous version, not sure why it was working, maybe because I had my
> printk's in it.
>
> I've also revised the indentation and now supports the 3 PCM
> streams, even though I seem to only be able to hear the first two when
> the mixer is set correctly.
thanks, the code looks nicer.
i noticed that you set the irq mask IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP.
does it mean that the chip generates interrupts twice per buffer?
if yes, what we need is to limit the number of periods to 2.
the attached patch includes some fixes by me for the latest cvs, and
changes the periods to 2. i'll apply it to cvs now.
Takashi
[-- Attachment #2: Type: text/plain, Size: 27461 bytes --]
Index: alsa-driver/pci/Kconfig
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-driver/pci/Kconfig,v
retrieving revision 1.16
diff -u -r1.16 Kconfig
--- alsa-driver/pci/Kconfig 3 Apr 2004 14:20:01 -0000 1.16
+++ alsa-driver/pci/Kconfig 14 May 2004 13:27:22 -0000
@@ -18,4 +18,12 @@
Say 'Y' or 'M' to include support for RME Hammerfall DSP MADI
soundcards.
+config SND_EMU10K1X
+ tristate "EMU10K1X (Dell OEM Version)"
+ depends on SND
+ select SND_AC97_CODEC
+ help
+ Say 'Y' or 'M' to include support for Sound Blaster Live Dell
+ OEM version.
+
endmenu
Index: alsa-driver/pci/emu10k1/Makefile
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-driver/pci/emu10k1/Makefile,v
retrieving revision 1.5
diff -u -r1.5 Makefile
--- alsa-driver/pci/emu10k1/Makefile 11 Nov 2003 13:09:46 -0000 1.5
+++ alsa-driver/pci/emu10k1/Makefile 14 May 2004 13:30:14 -0000
@@ -5,6 +5,10 @@
include $(SND_TOPDIR)/toplevel.config
include $(SND_TOPDIR)/Makefile.conf
+snd-emu10k1x-objs := emu10k1x.o
+
+obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o
+
export-objs := emu10k1_main.o
include $(SND_TOPDIR)/alsa-kernel/pci/emu10k1/Makefile
Index: alsa-driver/pci/emu10k1/emu10k1x.c
===================================================================
RCS file: alsa-driver/pci/emu10k1/emu10k1x.c
diff -N alsa-driver/pci/emu10k1/emu10k1x.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ alsa-driver/pci/emu10k1/emu10k1x.c 14 May 2004 13:32:26 -0000
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
+ * Driver EMU10K1X chips
+ *
+ * BUGS:
+ * --
+ *
+ * TODO:
+ * --
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+
+MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>");
+MODULE_DESCRIPTION("EMU10K1X");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Dell Creative Labs,SB Live!}");
+
+// module parameters (see "Module Parameters")
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static int boot_devs;
+
+module_param_array(index, int, boot_devs, 0444);
+MODULE_PARM_DESC(index, "Index value for the EMU10K1X soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+module_param_array(id, charp, boot_devs, 0444);
+MODULE_PARM_DESC(id, "ID string for the EMU10K1X soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+module_param_array(enable, bool, boot_devs, 0444);
+MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+
+
+// some definitions were borrowed from emu10k1 driver as they seem to be the same
+/************************************************************************************************/
+/* PCI function 0 registers, address = <val> + PCIBASE0 */
+/************************************************************************************************/
+
+#define PTR 0x00 /* Indexed register set pointer register */
+ /* NOTE: The CHANNELNUM and ADDRESS words can */
+ /* be modified independently of each other. */
+
+#define DATA 0x04 /* Indexed register set data register */
+
+#define IPR 0x08 /* Global interrupt pending register */
+ /* Clear pending interrupts by writing a 1 to */
+ /* the relevant bits and zero to the other bits */
+#define IPR_CH_0_LOOP 0x00000800 /* Channel 0 loop */
+#define IPR_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
+
+#define INTE 0x0c /* Interrupt enable register */
+#define INTE_CH_0_LOOP 0x00000800 /* Channel 0 loop */
+#define INTE_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */
+
+#define HCFG 0x14 /* Hardware config register */
+
+#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
+ /* NOTE: This should generally never be used. */
+#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */
+ /* Should be set to 1 when the EMU10K1 is */
+ /* completely initialized. */
+
+
+#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
+
+#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */
+
+#define SPCS0 0x42 /* SPDIF output Channel Status 0 register */
+
+#define SPCS1 0x43 /* SPDIF output Channel Status 1 register */
+
+#define SPCS2 0x44 /* SPDIF output Channel Status 2 register */
+
+#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */
+#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */
+#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */
+#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */
+#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */
+#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */
+#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */
+#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */
+#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */
+#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */
+#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */
+#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */
+#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */
+#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */
+#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */
+#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */
+#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */
+#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */
+#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */
+#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */
+#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */
+#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
+#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
+
+#define chip_t emu10k1x_t
+
+typedef struct snd_emu10k1x_voice emu10k1x_voice_t;
+typedef struct snd_emu10k1x emu10k1x_t;
+typedef struct snd_emu10k1x_pcm emu10k1x_pcm_t;
+
+struct snd_emu10k1x_voice {
+ emu10k1x_t *emu;
+ int number;
+ int use;
+ void (*interrupt)(emu10k1x_t *emu, emu10k1x_voice_t *pvoice);
+
+ emu10k1x_pcm_t *epcm;
+};
+
+struct snd_emu10k1x_pcm {
+ emu10k1x_t *emu;
+ snd_pcm_substream_t *substream;
+ emu10k1x_voice_t *voice;
+ unsigned short running;
+};
+
+// definition of the chip-specific record
+struct snd_emu10k1x {
+ snd_card_t *card;
+ struct pci_dev *pci;
+
+ unsigned long port;
+ struct resource *res_port;
+ int irq;
+
+ unsigned int revision; /* chip revision */
+ unsigned int serial; /* serial number */
+ unsigned short model; /* subsystem id */
+
+ spinlock_t emu_lock;
+ spinlock_t voice_lock;
+
+ ac97_t *ac97;
+ snd_pcm_t *pcm;
+
+ emu10k1x_voice_t voices[3];
+
+ struct snd_dma_device dma_dev;
+ struct snd_dma_buffer buffer;
+};
+
+#define emu10k1x_t_magic 0xa15a4501
+#define emu10k1x_pcm_t_magic 0xa15a4502
+
+/* hardware definition */
+static snd_pcm_hardware_t snd_emu10k1x_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (32*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (32*1024),
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 0,
+};
+
+static unsigned int snd_emu10k1x_ptr_read(emu10k1x_t * emu,
+ unsigned int reg,
+ unsigned int chn)
+{
+ unsigned long flags;
+ unsigned int regptr, val;
+
+ regptr = (reg << 16) | chn;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outl(regptr, emu->port + PTR);
+ val = inl(emu->port + DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ return val;
+}
+
+static void snd_emu10k1x_ptr_write(emu10k1x_t *emu,
+ unsigned int reg,
+ unsigned int chn,
+ unsigned int data)
+{
+ unsigned int regptr;
+ unsigned long flags;
+
+ regptr = (reg << 16) | chn;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outl(regptr, emu->port + PTR);
+ outl(data, emu->port + DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+static void snd_emu10k1x_intr_enable(emu10k1x_t *emu, unsigned int intrenb)
+{
+ unsigned long flags;
+ unsigned int enable;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ enable = inl(emu->port + INTE) | intrenb;
+ outl(enable, emu->port + INTE);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+static int voice_alloc(emu10k1x_t *emu, emu10k1x_voice_t **rvoice)
+{
+ emu10k1x_voice_t *voice;
+ int idx;
+
+ *rvoice = NULL;
+ for (idx = 0; idx < 3; idx ++) {
+ voice = &emu->voices[idx];
+ if (voice->use)
+ continue;
+ voice->use = 1;
+ *rvoice = voice;
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+static int snd_emu10k1x_voice_alloc(emu10k1x_t *emu, emu10k1x_voice_t **rvoice)
+{
+ unsigned long flags;
+ int result;
+
+ snd_assert(rvoice != NULL, return -EINVAL);
+
+ spin_lock_irqsave(&emu->voice_lock, flags);
+
+ result = voice_alloc(emu, rvoice);
+
+ spin_unlock_irqrestore(&emu->voice_lock, flags);
+
+ return result;
+}
+
+static int snd_emu10k1x_voice_free(emu10k1x_t *emu, emu10k1x_voice_t *pvoice)
+{
+ unsigned long flags;
+
+ snd_assert(pvoice != NULL, return -EINVAL);
+ spin_lock_irqsave(&emu->voice_lock, flags);
+
+ pvoice->interrupt = NULL;
+ pvoice->use = 0;
+ pvoice->epcm = NULL;
+
+ spin_unlock_irqrestore(&emu->voice_lock, flags);
+ return 0;
+}
+
+static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime)
+{
+ emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return);
+
+ if (epcm)
+ snd_magic_kfree(epcm);
+}
+
+static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice)
+{
+ emu10k1x_pcm_t *epcm;
+
+ if ((epcm = voice->epcm) == NULL)
+ return;
+ if (epcm->substream == NULL)
+ return;
+#if 0
+ printk("IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",
+ epcm->substream->runtime->hw->pointer(emu, epcm->substream),
+ snd_pcm_lib_period_bytes(epcm->substream),
+ snd_pcm_lib_buffer_bytes(epcm->substream));
+#endif
+ snd_pcm_period_elapsed(epcm->substream);
+}
+
+/* open callback */
+static int snd_emu10k1x_playback_open(snd_pcm_substream_t *substream)
+{
+ emu10k1x_t *chip = snd_pcm_substream_chip(substream);
+ emu10k1x_pcm_t *epcm;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+
+ epcm = snd_magic_kcalloc(emu10k1x_pcm_t, 0, GFP_KERNEL);
+ if (epcm == NULL)
+ return -ENOMEM;
+ epcm->emu = chip;
+ epcm->substream = substream;
+
+ runtime->private_data = epcm;
+ runtime->private_free = snd_emu10k1x_pcm_free_substream;
+
+ runtime->hw = snd_emu10k1x_playback_hw;
+
+ return 0;
+}
+
+/* close callback */
+static int snd_emu10k1x_playback_close(snd_pcm_substream_t *substream)
+{
+ return 0;
+}
+
+/* hw_params callback */
+static int snd_emu10k1x_pcm_hw_params(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ int err;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
+
+ if (! epcm->voice) {
+ if ((err = snd_emu10k1x_voice_alloc(epcm->emu, &epcm->voice)) < 0)
+ return err;
+ epcm->voice->epcm = epcm;
+ epcm->voice->interrupt = snd_emu10k1x_pcm_interrupt;
+ }
+
+ return snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+/* hw_free callback */
+static int snd_emu10k1x_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1x_pcm_t *epcm;
+
+ if (runtime->private_data == NULL)
+ return 0;
+ epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
+
+ if (epcm->voice) {
+ snd_emu10k1x_voice_free(epcm->emu, epcm->voice);
+ epcm->voice = NULL;
+ }
+
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* prepare callback */
+static int snd_emu10k1x_pcm_prepare(snd_pcm_substream_t *substream)
+{
+ emu10k1x_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
+ int voice = epcm->voice->number;
+
+ snd_emu10k1x_ptr_write(emu, 0x00, voice, 0);
+ snd_emu10k1x_ptr_write(emu, 0x01, voice, 0);
+ snd_emu10k1x_ptr_write(emu, 0x02, voice, 0);
+ snd_emu10k1x_ptr_write(emu, 0x04, voice, runtime->dma_addr);
+ snd_emu10k1x_ptr_write(emu, 0x05, voice, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
+ snd_emu10k1x_ptr_write(emu, 0x06, voice, 0);
+ snd_emu10k1x_ptr_write(emu, 0x07, voice, 0);
+ snd_emu10k1x_ptr_write(emu, 0x08, voice, 0);
+
+ return 0;
+}
+
+/* trigger callback */
+static int snd_emu10k1x_pcm_trigger(snd_pcm_substream_t *substream,
+ int cmd)
+{
+ emu10k1x_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
+ int channel = epcm->voice->number;
+ int result = 0;
+
+// printk("trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream));
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ snd_emu10k1x_ptr_write(emu, 0x40, 0, snd_emu10k1x_ptr_read(emu, 0x40, 0)|(1<<channel));
+ epcm->running = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ snd_emu10k1x_ptr_write(emu, 0x40, 0, snd_emu10k1x_ptr_read(emu, 0x40, 0) & ~(1<<channel));
+ epcm->running = 0;
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+ return result;
+}
+
+/* pointer callback */
+static snd_pcm_uframes_t
+snd_emu10k1x_pcm_pointer(snd_pcm_substream_t *substream)
+{
+ emu10k1x_t *emu = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ emu10k1x_pcm_t *epcm = snd_magic_cast(emu10k1x_pcm_t, runtime->private_data, return -ENXIO);
+ unsigned int ptr = 0;
+ int channel = epcm->voice->number;
+
+ if (!epcm->running)
+ return 0;
+
+ // printk("pointer: %08X %08X\n",
+ // snd_emu10k1x_ptr_read(emu, 0x06, channel),
+ // snd_emu10k1x_ptr_read(emu, 0x12, channel));
+ ptr = bytes_to_frames(runtime, snd_emu10k1x_ptr_read(emu, 0x06, channel));
+ if (ptr >= runtime->buffer_size)
+ ptr -= runtime->buffer_size;
+
+ // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
+ return ptr;
+}
+
+/* operators */
+static snd_pcm_ops_t snd_emu10k1x_playback_ops = {
+ .open = snd_emu10k1x_playback_open,
+ .close = snd_emu10k1x_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_emu10k1x_pcm_hw_params,
+ .hw_free = snd_emu10k1x_pcm_hw_free,
+ .prepare = snd_emu10k1x_pcm_prepare,
+ .trigger = snd_emu10k1x_pcm_trigger,
+ .pointer = snd_emu10k1x_pcm_pointer,
+};
+
+static unsigned short snd_emu10k1x_ac97_read(ac97_t *ac97,
+ unsigned short reg)
+{
+ emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, ac97->private_data, return -ENXIO);
+ unsigned long flags;
+ unsigned short val;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outb(reg, emu->port + AC97ADDRESS);
+ val = inw(emu->port + AC97DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ return val;
+}
+
+static void snd_emu10k1x_ac97_write(ac97_t *ac97,
+ unsigned short reg, unsigned short val)
+{
+ emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, ac97->private_data, return);
+ unsigned long flags;
+
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ outb(reg, emu->port + AC97ADDRESS);
+ outw(val, emu->port + AC97DATA);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+static int snd_emu10k1x_ac97(emu10k1x_t *chip)
+{
+ ac97_bus_t bus, *pbus;
+ ac97_t ac97;
+ int err;
+
+ memset(&bus, 0, sizeof(bus));
+ bus.write = snd_emu10k1x_ac97_write;
+ bus.read = snd_emu10k1x_ac97_read;
+ if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
+ return err;
+ memset(&ac97, 0, sizeof(ac97));
+ ac97.private_data = chip;
+ return snd_ac97_mixer(pbus, &ac97, &chip->ac97);
+}
+
+static int snd_emu10k1x_free(emu10k1x_t *chip)
+{
+ snd_emu10k1x_ptr_write(chip, 0x40, 0, 0);
+ // disable interrupts
+ outl(0, chip->port + INTE);
+ // disable audio
+ outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);
+
+ // release the i/o port
+ if (chip->res_port) {
+ release_resource(chip->res_port);
+ kfree_nocheck(chip->res_port);
+ }
+ // release the irq
+ if (chip->irq >= 0)
+ free_irq(chip->irq, (void *)chip);
+ // release the data
+ snd_magic_kfree(chip);
+ return 0;
+}
+
+static int snd_emu10k1x_dev_free(snd_device_t *device)
+{
+ emu10k1x_t *chip = snd_magic_cast(emu10k1x_t,
+ device->device_data, return -ENXIO);
+ return snd_emu10k1x_free(chip);
+}
+
+static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned int status;
+
+ emu10k1x_t *chip = snd_magic_cast(emu10k1x_t, dev_id, return IRQ_NONE);
+ int i;
+ int mask;
+
+ spin_lock(&chip->emu_lock);
+
+ status = inl(chip->port + IPR);
+
+ // call updater, unlock before it
+ spin_unlock(&chip->emu_lock);
+
+ if (! status)
+ return IRQ_NONE;
+
+ mask = IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP;
+ for(i = 0; i < 3; i++) {
+ emu10k1x_voice_t *pvoice = chip->voices;
+ if(status & mask) {
+ if(pvoice->use && pvoice->interrupt)
+ pvoice->interrupt(chip, pvoice);
+ }
+ pvoice++;
+ mask <<= 1;
+ }
+ spin_lock(&chip->emu_lock);
+ // acknowledge the interrupt if necessary
+ outl(status, chip->port+IPR);
+
+ spin_unlock(&chip->emu_lock);
+
+ // printk(KERN_INFO "interrupt %08x\n", status);
+
+ return IRQ_HANDLED;
+}
+
+static void snd_emu10k1x_pcm_free(snd_pcm_t *pcm)
+{
+ emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, pcm->private_data, return);
+ emu->pcm = NULL;
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __devinit snd_emu10k1x_pcm(emu10k1x_t *emu, int device, snd_pcm_t **rpcm)
+{
+ snd_pcm_t *pcm;
+ snd_pcm_substream_t *substream;
+ int err;
+
+ if (rpcm)
+ *rpcm = NULL;
+
+ if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 3, 0, &pcm)) < 0)
+ return err;
+
+ pcm->private_data = emu;
+ pcm->private_free = snd_emu10k1x_pcm_free;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops);
+ // snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1x_capture_ops);
+
+ pcm->info_flags = 0;
+ pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
+ strcpy(pcm->name, "EMU10K1X");
+ emu->pcm = pcm;
+
+ for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ substream;
+ substream = substream->next)
+ if ((err = snd_pcm_lib_preallocate_pages(substream,
+ SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(emu->pci),
+ 32*1024, 32*1024)) < 0)
+ return err;
+
+ /*
+ for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+ substream;
+ substream = substream->next)
+ snd_pcm_lib_preallocate_pages(substream,
+ SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(emu->pci),
+ 64*1024, 64*1024);
+ */
+
+ if (rpcm)
+ *rpcm = pcm;
+
+ return 0;
+}
+
+static int __devinit snd_emu10k1x_create(snd_card_t *card,
+ struct pci_dev *pci,
+ emu10k1x_t **rchip)
+{
+ emu10k1x_t *chip;
+ int err;
+ int ch;
+ static snd_device_ops_t ops = {
+ .dev_free = snd_emu10k1x_dev_free,
+ };
+
+ *rchip = NULL;
+
+ if ((err = pci_enable_device(pci)) < 0)
+ return err;
+ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
+ pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+ printk(KERN_ERR "error to set 28bit mask DMA\n");
+ return -ENXIO;
+ }
+
+ chip = snd_magic_kcalloc(emu10k1x_t, 0, GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->card = card;
+ chip->pci = pci;
+ chip->irq = -1;
+
+ spin_lock_init(&chip->emu_lock);
+ spin_lock_init(&chip->voice_lock);
+
+ chip->port = pci_resource_start(pci, 0);
+ if ((chip->res_port = request_region(chip->port, 8,
+ "My Chip")) == NULL) {
+ snd_emu10k1x_free(chip);
+ printk(KERN_ERR "cannot allocate the port\n");
+ return -EBUSY;
+ }
+
+ if (request_irq(pci->irq, snd_emu10k1x_interrupt,
+ SA_INTERRUPT|SA_SHIRQ, "EMU10K1X",
+ (void *)chip)) {
+ snd_emu10k1x_free(chip);
+ printk(KERN_ERR "cannot grab irq\n");
+ return -EBUSY;
+ }
+ chip->irq = pci->irq;
+
+ memset(&chip->dma_dev, 0, sizeof(chip->dma_dev));
+ chip->dma_dev.type = SNDRV_DMA_TYPE_DEV;
+ chip->dma_dev.dev = snd_dma_pci_data(pci);
+
+ if(snd_dma_alloc_pages(&chip->dma_dev, 32 * 1024, &chip->buffer) < 0) {
+ snd_emu10k1x_free(chip);
+ return -ENOMEM;
+ }
+
+ pci_set_master(pci);
+ /* read revision & serial */
+ pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision);
+ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
+ pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
+ printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
+ chip->revision, chip->serial);
+
+ outl(0, chip->port + INTE);
+
+ for(ch = 0; ch < 3; ch++) {
+ chip->voices[ch].emu = chip;
+ chip->voices[ch].number = ch;
+ }
+
+ /*
+ * Init to 0x02109204 :
+ * Clock accuracy = 0 (1000ppm)
+ * Sample Rate = 2 (48kHz)
+ * Audio Channel = 1 (Left of 2)
+ * Source Number = 0 (Unspecified)
+ * Generation Status = 1 (Original for Cat Code 12)
+ * Cat Code = 12 (Digital Signal Mixer)
+ * Mode = 0 (Mode 0)
+ * Emphasis = 0 (None)
+ * CP = 1 (Copyright unasserted)
+ * AN = 0 (Audio data)
+ * P = 0 (Consumer)
+ */
+ snd_emu10k1x_ptr_write(chip, SPCS0, 0,
+ SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
+ SPCS_GENERATIONSTATUS | 0x00001200 |
+ 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+ snd_emu10k1x_ptr_write(chip, SPCS1, 0,
+ SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
+ SPCS_GENERATIONSTATUS | 0x00001200 |
+ 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+ snd_emu10k1x_ptr_write(chip, SPCS2, 0,
+ SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
+ SPCS_GENERATIONSTATUS | 0x00001200 |
+ 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+ snd_emu10k1x_ptr_write(chip, 0x41, 0, 0x70f); // ???
+ snd_emu10k1x_ptr_write(chip, 0x45, 0, 0);
+
+ outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG);
+
+ snd_emu10k1x_intr_enable(chip, (INTE_CH_0_LOOP|INTE_CH_0_HALF_LOOP));
+ // snd_emu10k1x_intr_enable(chip, (INTE_CH_0_LOOP<<1);
+ // snd_emu10k1x_intr_enable(chip, INTE_CH_0_LOOP<<2);
+
+ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+ chip, &ops)) < 0) {
+ snd_emu10k1x_free(chip);
+ return err;
+ }
+ *rchip = chip;
+ return 0;
+}
+
+static void snd_emu10k1x_proc_reg_read(snd_info_entry_t *entry,
+ snd_info_buffer_t * buffer)
+{
+ emu10k1x_t *emu = snd_magic_cast(emu10k1x_t, entry->private_data, return);
+ snd_iprintf(buffer, "Registers:\n\n");
+ unsigned long value,value1,value2;
+ unsigned long flags;
+ int i;
+ for(i = 0; i < 0x40; i+=4) {
+ spin_lock_irqsave(&emu->emu_lock, flags);
+ value = inl(emu->port + i);
+ spin_unlock_irqrestore(&emu->emu_lock, flags);
+ snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
+ }
+ snd_iprintf(buffer, "\nRegisters\n\n");
+ for(i = 0; i < 0x50; i++) {
+ value = snd_emu10k1x_ptr_read(emu, i, 0);
+ value1 = snd_emu10k1x_ptr_read(emu, i, 1);
+ value2 = snd_emu10k1x_ptr_read(emu, i, 2);
+ snd_iprintf(buffer, "%02X: %08lX %08lX %08lX\n", i, value, value, value2);
+ }
+}
+
+int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu)
+{
+ snd_info_entry_t *entry;
+
+ if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry))
+ snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read);
+ return 0;
+}
+
+static int __devinit snd_emu10k1x_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ static int dev;
+ snd_card_t *card;
+ emu10k1x_t *chip;
+ int err;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ if (card == NULL)
+ return -ENOMEM;
+
+ if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ if ((err = snd_emu10k1x_ac97(chip)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ snd_emu10k1x_proc_init(chip);
+
+ strcpy(card->driver, "Dell SB Live");
+ strcpy(card->shortname, "EMU10K1X");
+ sprintf(card->longname, "%s at 0x%lx irq %i",
+ card->shortname, chip->port, chip->irq);
+
+ if ((err = snd_card_register(card)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ pci_set_drvdata(pci, card);
+ dev++;
+ return 0;
+}
+
+static void __devexit snd_emu10k1x_remove(struct pci_dev *pci)
+{
+ snd_card_free(pci_get_drvdata(pci));
+ pci_set_drvdata(pci, NULL);
+}
+
+// PCI IDs
+static struct pci_device_id snd_emu10k1x_ids[] = {
+ { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
+
+// pci_driver definition
+static struct pci_driver driver = {
+ .name = "Emu10k1x",
+ .id_table = snd_emu10k1x_ids,
+ .probe = snd_emu10k1x_probe,
+ .remove = __devexit_p(snd_emu10k1x_remove),
+};
+
+// initialization of the module
+static int __init alsa_card_emu10k1x_init(void)
+{
+ int err;
+
+ if ((err = pci_module_init(&driver)) > 0)
+ return err;
+
+ return 0;
+}
+
+// clean up the module
+static void __exit alsa_card_emu10k1x_exit(void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_emu10k1x_init)
+module_exit(alsa_card_emu10k1x_exit)
+
+EXPORT_NO_SYMBOLS; /* for old kernels only */
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: Emu10k1x driver
2004-05-14 13:35 ` Takashi Iwai
@ 2004-05-14 23:49 ` Francisco Moraes
0 siblings, 0 replies; 17+ messages in thread
From: Francisco Moraes @ 2004-05-14 23:49 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
Takashi Iwai wrote:
>i noticed that you set the irq mask IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP.
>does it mean that the chip generates interrupts twice per buffer?
>if yes, what we need is to limit the number of periods to 2.
>
>
>
Well, you can enable the half buffer interrupt. I am not sure if that
helps or improves anything but it is available.
>the attached patch includes some fixes by me for the latest cvs, and
>changes the periods to 2. i'll apply it to cvs now.
>
>
I also noticed that I forgot to enable the interrupts for the other two
voices.
Francisco
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
@ 2004-05-14 17:02 fmoraes74
0 siblings, 0 replies; 17+ messages in thread
From: fmoraes74 @ 2004-05-14 17:02 UTC (permalink / raw)
To: tiwai; +Cc: fmoraes74, alsa-devel
> i noticed that you set the irq mask IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP.
> does it mean that the chip generates interrupts twice per buffer?
> if yes, what we need is to limit the number of periods to 2.
The hardware can generate an interrupt at the beginning or the period (ptr = 0) and the middle of the period (halfway through the buffer). I didn't much time trying to understand all the internals of ALSA, so I submitted what worked. This latest version has alsaplayer working and the pcm test in alsa-lib.
I've two channels playback but the third one cannot be heard (there seems to be no mixer control for it), so we probably need the specs to figure that one out.
> the attached patch includes some fixes by me for the latest cvs, and
> changes the periods to 2. I'll apply it to cvs now.
Thanks,
Francisco
________________________________________________________________
The best thing to hit the Internet in years - NetZero HiSpeed!
Surf the Web up to FIVE TIMES FASTER!
Only $14.95/ month -visit www.netzero.com to sign up today!
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
@ 2004-05-15 1:30 fmoraes74
2004-05-15 13:18 ` Takashi Iwai
0 siblings, 1 reply; 17+ messages in thread
From: fmoraes74 @ 2004-05-15 1:30 UTC (permalink / raw)
To: fmoraes74; +Cc: tiwai, alsa-devel
>the attached patch includes some fixes by me for the latest cvs, and
>changes the periods to 2. i'll apply it to cvs now.
Is your patch for kernel 2.6?
Francisco
________________________________________________________________
The best thing to hit the Internet in years - NetZero HiSpeed!
Surf the Web up to FIVE TIMES FASTER!
Only $14.95/ month -visit www.netzero.com to sign up today!
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-15 1:30 fmoraes74
@ 2004-05-15 13:18 ` Takashi Iwai
2004-05-15 21:30 ` Francisco Moraes
0 siblings, 1 reply; 17+ messages in thread
From: Takashi Iwai @ 2004-05-15 13:18 UTC (permalink / raw)
To: fmoraes74; +Cc: alsa-devel
At Sat, 15 May 2004 01:30:51 GMT,
fmoraes74@netzero.net wrote:
>
>
> >the attached patch includes some fixes by me for the latest cvs, and
> >changes the periods to 2. i'll apply it to cvs now.
>
> Is your patch for kernel 2.6?
to the latest ALSA cvs.
you'd better to get the CVS tree (either via cvs or snapshot).
it already incldues emu10k1x.c.
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-15 13:18 ` Takashi Iwai
@ 2004-05-15 21:30 ` Francisco Moraes
2004-05-16 14:59 ` Takashi Iwai
0 siblings, 1 reply; 17+ messages in thread
From: Francisco Moraes @ 2004-05-15 21:30 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
Takashi Iwai wrote:
>>Is your patch for kernel 2.6?
>>
>>
>
>to the latest ALSA cvs.
>you'd better to get the CVS tree (either via cvs or snapshot).
>it already incldues emu10k1x.c.
>
>
I got it from there but your changes to add the module params don't
compile on my system (Red Hat Fedora Core 1 - 2.4.22-2188 kernel).
There is also a problem with mono streams, so the hw params need to
indicate that only stereo is supported. Also, is there any advantage in
enabling both interrupts in the buffer (loop and half loop)? Also, how
important is the definition of period bytes? It seems it should be the
same as the buffer size. Maybe you can just explain it to me how it
relates to the total buffer size being used.
Regards,
Francisco
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Emu10k1x driver
2004-05-15 21:30 ` Francisco Moraes
@ 2004-05-16 14:59 ` Takashi Iwai
0 siblings, 0 replies; 17+ messages in thread
From: Takashi Iwai @ 2004-05-16 14:59 UTC (permalink / raw)
To: Francisco Moraes; +Cc: alsa-devel
At Sat, 15 May 2004 17:30:52 -0400,
Francisco Moraes wrote:
>
> Takashi Iwai wrote:
>
> >>Is your patch for kernel 2.6?
> >>
> >>
> >
> >to the latest ALSA cvs.
> >you'd better to get the CVS tree (either via cvs or snapshot).
> >it already incldues emu10k1x.c.
> >
> >
> I got it from there but your changes to add the module params don't
> compile on my system (Red Hat Fedora Core 1 - 2.4.22-2188 kernel).
did you rebuild via cvscompile script?
> There is also a problem with mono streams, so the hw params need to
> indicate that only stereo is supported.
that's fine. many hardwares support only stereo indeed.
> Also, is there any advantage in
> enabling both interrupts in the buffer (loop and half loop)?
yes, definitely. (IIRC, it IS enabled?)
otherwise the app won't work proprely in most cases.
remember that the sound system is driven by interrupts.
an irq per buffer means that we have only one chance to update the
data in the accurate timinig.
> Also, how
> important is the definition of period bytes? It seems it should be the
> same as the buffer size.
no, it should be a half of the buffer size.
> Maybe you can just explain it to me how it
> relates to the total buffer size being used.
the buffer size is the total size of the memory space you callocate.
when the amount of processed PCM data becomes to the period size, an
irq is issued. in the case of emu10k1x, hence, period size is ALWAYS
buffer size / 2 (as long as half-interrupt bit is set).
Takashi
-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2004-05-16 14:59 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-12 0:31 Emu10k1x driver fmoraes74
2004-05-12 2:16 ` James Courtier-Dutton
2004-05-12 2:46 ` Francisco Moraes
2004-05-14 16:55 ` Takashi Iwai
2004-05-14 17:14 ` James Courtier-Dutton
2004-05-14 17:32 ` Takashi Iwai
2004-05-14 18:48 ` James Courtier-Dutton
2004-05-12 11:05 ` Takashi Iwai
-- strict thread matches above, loose matches on Subject: below --
2004-05-12 18:36 fmoraes74
2004-05-13 13:17 ` Takashi Iwai
[not found] <20040514.045055.28422.197543@webmail10.nyc.untd.com>
2004-05-14 13:35 ` Takashi Iwai
2004-05-14 23:49 ` Francisco Moraes
2004-05-14 17:02 fmoraes74
2004-05-15 1:30 fmoraes74
2004-05-15 13:18 ` Takashi Iwai
2004-05-15 21:30 ` Francisco Moraes
2004-05-16 14:59 ` Takashi Iwai
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.