Commit e2fa3083 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Linus Torvalds

[PATCH] ALSA update [8/10] - 2002/07/31

  - AC'97 codec
    - added reset callback to do reset and skip the standard procedure
    - added limited_regs flag to avoid to touch unexpected registers
    - Fixes for AD1981A and added a special patch for an intel motherboard
  - sequencer
    - check the possible infinite loop in priority queues
    - reset the timer at continue if not initialized yet
  - changed synchronize_irq() for new api with an argument
  - NM256 driver - fixes the lock up on NM256 ZX
  - VIA8233 - implementation of SG buffer
parent b21fd933
......@@ -152,6 +152,7 @@
typedef struct _snd_ac97 ac97_t;
struct _snd_ac97 {
void (*reset) (ac97_t *ac97);
void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val);
unsigned short (*read) (ac97_t *ac97, unsigned short reg);
void (*wait) (ac97_t *ac97);
......@@ -178,6 +179,7 @@ struct _snd_ac97 {
unsigned int rates_mic_adc;
unsigned int spdif_status;
unsigned short regs[0x80]; /* register cache */
unsigned int limited_regs; /* allow limited registers only */
bitmap_member(reg_accessed,0x80); /* bit flags */
union { /* vendor specific code */
struct {
......
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2"
#define CONFIG_SND_DATE " (Wed Jul 24 10:42:45 2002 UTC)"
#define CONFIG_SND_DATE " (Wed Jul 31 15:28:28 2002 UTC)"
......@@ -146,20 +146,15 @@ static inline int compare_timestamp_rel(snd_seq_event_t *a, snd_seq_event_t *b)
}
/* enqueue cell to prioq */
void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
{
snd_seq_event_cell_t *cur, *prev;
unsigned long flags;
int count;
int prior;
if (f == NULL) {
snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
return;
}
if (cell == NULL) {
snd_printd("oops: snd_seq_prioq_cell_in() called with NULL cell\n");
return;
}
snd_assert(f, return -EINVAL);
snd_assert(cell, return -EINVAL);
/* check flags */
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
......@@ -177,7 +172,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
return;
return 0;
}
}
/* traverse list of elements to find the place where the new cell is
......@@ -186,6 +181,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
prev = NULL; /* previous cell */
cur = f->head; /* cursor */
count = 10000; /* FIXME: enough big, isn't it? */
while (cur != NULL) {
/* compare timestamps */
int rel = compare_timestamp_rel(&cell->event, &cur->event);
......@@ -199,6 +195,11 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
/* move cursor to next cell */
prev = cur;
cur = cur->next;
if (! --count) {
spin_unlock_irqrestore(&f->lock, flags);
snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
return -EINVAL;
}
}
/* insert it before cursor */
......@@ -212,6 +213,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
return 0;
}
/* dequeue cell from prioq */
......
......@@ -41,7 +41,7 @@ extern prioq_t *snd_seq_prioq_new(void);
extern void snd_seq_prioq_delete(prioq_t **fifo);
/* enqueue cell to prioq */
extern void snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
extern int snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
/* dequeue cell from prioq */
extern snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t *f);
......
......@@ -365,9 +365,11 @@ void snd_seq_timer_continue(seq_timer_t * tmr)
return;
if (tmr->running)
return;
if (! tmr->initialized)
if (! tmr->initialized) {
snd_seq_timer_reset(tmr);
if (initialize_timer(tmr) < 0)
return;
}
snd_timer_start(tmr->timeri, tmr->ticks);
tmr->running = 1;
do_gettimeofday(&tmr->last_update);
......
......@@ -168,7 +168,7 @@ static int __init snd_card_dt019x_isapnp(int dev, struct snd_card_dt019x *acard)
snd_dma8[dev] = pdev->dma_resource[0].start;
snd_irq[dev] = pdev->irq_resource[0].start;
snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%lx, dma=0x%lx\n",
snd_port[dev],snd_irq[dev],smd_dma8[dev]);
snd_port[dev],snd_irq[dev],snd_dma8[dev]);
pdev = acard->devmpu;
if (!pdev || pdev->prepare(pdev)<0)
......
......@@ -91,10 +91,10 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819 },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881 },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881 },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1881 },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885 },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445372, 0xffffffff, "AD1981A", NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL },
......@@ -240,12 +240,11 @@ void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value
set_bit(reg, ac97->reg_accessed);
}
#ifndef CONFIG_SND_DEBUG
#define snd_ac97_write_cache_test snd_ac97_write_cache
#else
static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned short value)
{
return snd_ac97_write_cache(ac97, reg, value);
if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
return;
#if 0
if (!snd_ac97_valid_reg(ac97, reg))
return;
spin_lock(&ac97->reg_lock);
......@@ -254,8 +253,9 @@ static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned
if (value != ac97->regs[reg])
snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]);
spin_unlock(&ac97->reg_lock);
}
#endif
snd_ac97_write_cache(ac97, reg, value);
}
int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
{
......@@ -911,6 +911,9 @@ static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg)
{
unsigned short val, mask = 0x8000;
if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
return 0;
switch (reg) {
case AC97_MASTER_TONE:
return ac97->caps & 0x04 ? 1 : 0;
......@@ -1461,6 +1464,12 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
*ac97 = *_ac97;
ac97->card = card;
spin_lock_init(&ac97->reg_lock);
if (ac97->reset) {
ac97->reset(ac97);
goto __access_ok;
}
snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */
if (ac97->wait)
ac97->wait(ac97);
......@@ -1499,6 +1508,10 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
snd_ac97_free(ac97);
return -EIO;
}
if (ac97->reset) // FIXME: always skipping?
goto __ready_ok;
/* FIXME: add powerdown control */
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
......@@ -1540,6 +1553,7 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates_lfe_dac);
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
}
/* additional initializations */
if (ac97->init)
ac97->init(ac97);
snd_ac97_get_name(ac97, ac97->id, name);
......@@ -1738,7 +1752,10 @@ static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffe
int reg, val;
for (reg = 0; reg < 0x80; reg += 2) {
val = snd_ac97_read(ac97, reg);
if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
val = 0xffff;
else
val = snd_ac97_read(ac97, reg);
snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val);
}
}
......@@ -1903,6 +1920,11 @@ void snd_ac97_resume(ac97_t *ac97)
{
int i;
if (ac97->reset) {
ac97->reset(ac97);
goto __reset_ready;
}
snd_ac97_write(ac97, AC97_POWERDOWN, 0);
snd_ac97_write(ac97, AC97_RESET, 0);
udelay(100);
......@@ -1916,6 +1938,7 @@ void snd_ac97_resume(ac97_t *ac97)
break;
mdelay(1);
}
__reset_ready:
if (ac97->init)
ac97->init(ac97);
......
......@@ -300,6 +300,20 @@ int patch_ad1881(ac97_t * ac97)
return 0;
}
int patch_ad1885(ac97_t * ac97)
{
unsigned short jack;
patch_ad1881(ac97);
/* This is required to deal with the Intel D815EEAL2 */
/* i.e. Line out is actually headphone out from codec */
/* turn off jack sense bits D8 & D9 */
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
return 0;
}
int patch_ad1886(ac97_t * ac97)
{
patch_ad1881(ac97);
......
......@@ -35,4 +35,5 @@ int patch_cirrus_spdif(ac97_t * ac97);
int patch_conexant(ac97_t * ac97);
int patch_ad1819(ac97_t * ac97);
int patch_ad1881(ac97_t * ac97);
int patch_ad1885(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97);
......@@ -1970,9 +1970,10 @@ static void snd_ali_resume(struct pci_dev *dev)
static int snd_ali_free(ali_t * codec)
{
snd_ali_disable_address_interrupt(codec);
synchronize_irq(codec->irq);
if (codec->irq >=0)
if (codec->irq >= 0) {
synchronize_irq(codec->irq);
free_irq(codec->irq, (void *)codec);
}
if (codec->res_port) {
release_resource(codec->res_port);
kfree_nocheck(codec->res_port);
......
......@@ -1300,7 +1300,7 @@ static int snd_cs4281_free(cs4281_t *chip)
}
#endif
snd_cs4281_proc_done(chip);
if(chip->irq >= 0)
if (chip->irq >= 0)
synchronize_irq(chip->irq);
/* Mask interrupts */
......
......@@ -64,7 +64,7 @@ static void mpu401_clear_rx(emu10k1_t *emu, emu10k1_midi_t *mpu)
mpu401_read_data(emu, mpu);
#ifdef CONFIG_SND_DEBUG
if (timeout <= 0)
snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
#endif
}
......@@ -143,7 +143,7 @@ static void snd_emu10k1_midi_cmd(emu10k1_t * emu, emu10k1_midi_t *midi, unsigned
}
spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok)
snd_printk("midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
cmd, emu->port,
mpu401_read_stat(emu, midi),
mpu401_read_data(emu, midi));
......
......@@ -968,11 +968,13 @@ static void snd_emu10k1_pcm_free(snd_pcm_t *pcm)
{
emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return);
emu->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
snd_pcm_substream_t *substream;
int err;
if (rpcm)
......@@ -992,6 +994,10 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
strcpy(pcm->name, "EMU10K1");
emu->pcm = pcm;
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pci_pages(emu->pci, substream, 64*1024, 64*1024);
return err;
if (rpcm)
*rpcm = pcm;
......
......@@ -1532,8 +1532,7 @@ static int snd_ensoniq_free(ensoniq_t *ensoniq)
outl(0, ES_REG(ensoniq, CONTROL)); /* switch everything off */
outl(0, ES_REG(ensoniq, SERIAL)); /* clear serial interface */
#endif
if(ensoniq->irq >= 0)
synchronize_irq(ensoniq->irq);
synchronize_irq(ensoniq->irq);
pci_set_power_state(ensoniq->pci, 3);
__hw_end:
#ifdef CHIP1370
......
......@@ -4072,7 +4072,7 @@ static int snd_ice1712_free(ice1712_t *ice)
/* --- */
__hw_end:
snd_ice1712_proc_done(ice);
if (ice->irq) {
if (ice->irq >= 0) {
synchronize_irq(ice->irq);
free_irq(ice->irq, (void *) ice);
}
......@@ -4146,7 +4146,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card,
pci_write_config_word(ice->pci, 0x40, 0x807f);
pci_write_config_word(ice->pci, 0x42, 0x0006);
snd_ice1712_proc_init(ice);
synchronize_irq(ice->irq);
synchronize_irq(pci->irq);
if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
snd_ice1712_free(ice);
......
......@@ -1104,8 +1104,7 @@ static int snd_intel8x0_free(intel8x0_t *chip)
outb(ICH_RESETREGS, ICHREG(chip, PO_CR));
outb(ICH_RESETREGS, ICHREG(chip, MC_CR));
/* --- */
if(chip->irq >= 0)
synchronize_irq(chip->irq);
synchronize_irq(chip->irq);
__hw_end:
if (chip->bdbars)
snd_free_pci_pages(chip->pci, 3 * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr);
......
......@@ -2310,7 +2310,7 @@ static int snd_m3_free(m3_t *chip)
vfree(chip->suspend_mem);
#endif
if(chip->irq >= 0)
if (chip->irq >= 0)
synchronize_irq(chip->irq);
if (chip->iobase_res) {
......
......@@ -892,7 +892,7 @@ static snd_pcm_ops_t snd_nm256_capture_ops = {
#endif
};
static int __init
static int __devinit
snd_nm256_pcm(nm256_t *chip, int device)
{
snd_pcm_t *pcm;
......@@ -1188,21 +1188,31 @@ snd_nm256_ac97_reset(ac97_t *ac97)
}
/* create an ac97 mixer interface */
static int __init
static int __devinit
snd_nm256_mixer(nm256_t *chip)
{
ac97_t ac97;
int err;
int i;
/* looks like nm256 hangs up when unexpected registers are touched... */
static int mixer_regs[] = {
AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO,
AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE,
AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
AC97_EXTENDED_ID, AC97_EXTENDED_STATUS,
AC97_VENDOR_ID1, AC97_VENDOR_ID2,
-1
};
memset(&ac97, 0, sizeof(ac97));
ac97.init = snd_nm256_ac97_reset;
ac97.reset = snd_nm256_ac97_reset;
ac97.write = snd_nm256_ac97_write;
ac97.read = snd_nm256_ac97_read;
ac97.limited_regs = 1;
for (i = 0; mixer_regs[i] >= 0; i++)
set_bit(mixer_regs[i], ac97.reg_accessed);
ac97.private_data = chip;
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
return err;
return 0;
return snd_ac97_mixer(chip->card, &ac97, &chip->ac97);
}
/*
......@@ -1211,7 +1221,7 @@ snd_nm256_mixer(nm256_t *chip)
* RAM.
*/
static int __init
static int __devinit
snd_nm256_peek_for_sig(nm256_t *chip)
{
/* The signature is located 1K below the end of video RAM. */
......@@ -1346,7 +1356,7 @@ static int snd_nm256_free(nm256_t *chip)
if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
snd_nm256_capture_stop(chip);
if(chip->irq >= 0)
if (chip->irq >= 0)
synchronize_irq(chip->irq);
if (chip->cport)
......@@ -1374,7 +1384,7 @@ static int snd_nm256_dev_free(snd_device_t *device)
return snd_nm256_free(chip);
}
static int __init
static int __devinit
snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
int play_bufsize, int capt_bufsize,
int force_load,
......
......@@ -238,7 +238,7 @@ struct _snd_via686a {
snd_card_t *card;
snd_pcm_t *pcm;
snd_pcm_t *pcm_fm;
/*snd_pcm_t *pcm_fm;*/
viadev_t playback;
viadev_t capture;
/*viadev_t playback_fm;*/
......@@ -564,8 +564,13 @@ static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev
val = 0;
else
val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
} else {
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
viadev->lastptr = ptr;
viadev->lastcount = count;
// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
......@@ -632,10 +637,10 @@ static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
chip->playback.substream = substream;
runtime->hw = snd_via686a_playback;
runtime->hw.rates = chip->ac97->rates_front_dac;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
......@@ -658,10 +663,10 @@ static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
chip->capture.substream = substream;
runtime->hw = snd_via686a_capture;
runtime->hw.rates = chip->ac97->rates_adc;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
......@@ -1020,7 +1025,7 @@ static int __devinit snd_via686a_create(snd_card_t * card,
if (ac97_clock >= 8000 && ac97_clock <= 48000)
chip->ac97_clock = ac97_clock;
pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
synchronize_irq(pci->irq);
synchronize_irq(chip->irq);
/* initialize offsets */
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
......
......@@ -29,6 +29,8 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_sgbuf.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/ac97_codec.h>
#include <sound/mpu401.h>
......@@ -157,11 +159,8 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA_REG_AC97_DATA_MASK 0xffff
#define VIA_REG_SGD_SHADOW 0x84 /* dword */
/*
*
*/
#define VIA_MAX_FRAGS 32
#define VIA_TBL_BIT_FLAG 0x40000000
#define VIA_TBL_BIT_EOL 0x80000000
/*
*
......@@ -169,15 +168,78 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
typedef struct {
unsigned long reg_offset;
unsigned int *table;
dma_addr_t table_addr;
snd_pcm_substream_t *substream;
dma_addr_t physbuf;
int running;
unsigned int size;
unsigned int fragsize;
unsigned int frags;
unsigned int page_per_frag;
unsigned int curidx;
unsigned int tbl_entries; /* number of descriptor table entries */
unsigned int tbl_size; /* size of a table entry */
u32 *table; /* physical address + flag */
dma_addr_t table_addr;
} viadev_t;
static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
struct pci_dev *pci)
{
int i, size;
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
if (dev->table) {
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
}
/* allocate buffer descriptor lists */
if (dev->fragsize < PAGE_SIZE) {
dev->tbl_size = dev->fragsize;
dev->tbl_entries = dev->frags;
dev->page_per_frag = 1;
} else {
dev->tbl_size = PAGE_SIZE;
dev->tbl_entries = sgbuf->pages;
dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
}
/* the start of each lists must be aligned to 8 bytes,
* but the kernel pages are much bigger, so we don't care
*/
dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
if (! dev->table)
return -ENOMEM;
if (dev->tbl_size < PAGE_SIZE) {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
} else {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
}
size = dev->size;
for (i = 0; i < dev->tbl_entries - 1; i++) {
dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
size -= dev->tbl_size;
}
dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
return 0;
}
static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
struct pci_dev *pci)
{
if (dev->table) {
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
}
}
/*
*/
typedef struct _snd_via8233 via8233_t;
#define chip_t via8233_t
......@@ -200,9 +262,6 @@ struct _snd_via8233 {
spinlock_t reg_lock;
snd_info_entry_t *proc_entry;
void *tables;
dma_addr_t tables_addr;
};
static struct pci_device_id snd_via8233_ids[] __devinitdata = {
......@@ -323,15 +382,19 @@ static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = VIA_REG_CTRL_INT;
viadev->running = 0;
break;
default:
return -EINVAL;
......@@ -342,21 +405,33 @@ static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
return 0;
}
static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
static int snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
int idx, frags;
unsigned int *table = viadev->table;
unsigned long port = chip->port + viadev->reg_offset;
int v, err;
viadev->physbuf = runtime->dma_addr;
viadev->size = snd_pcm_lib_buffer_bytes(substream);
viadev->fragsize = snd_pcm_lib_period_bytes(substream);
viadev->frags = runtime->periods;
viadev->curidx = 0;
/* the period size must be in power of 2 */
v = ld2(viadev->fragsize);
if (viadev->fragsize != (1 << v)) {
snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
return -EINVAL;
}
snd_via8233_channel_reset(chip, viadev);
outl(viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
err = build_via_table(viadev, substream, chip->pci);
if (err < 0)
return err;
runtime->dma_bytes = viadev->size;
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
unsigned int slots;
int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
......@@ -378,27 +453,7 @@ static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
}
if (viadev->size == viadev->fragsize) {
table[0] = cpu_to_le32(viadev->physbuf);
table[1] = cpu_to_le32(0xc0000000 | /* EOL + flag */
viadev->fragsize);
} else {
frags = viadev->size / viadev->fragsize;
for (idx = 0; idx < frags - 1; idx++) {
table[(idx << 1) + 0] = cpu_to_le32(viadev->physbuf + (idx * viadev->fragsize));
table[(idx << 1) + 1] = cpu_to_le32(0x40000000 | /* flag */
viadev->fragsize);
}
table[((frags-1) << 1) + 0] = cpu_to_le32(viadev->physbuf + ((frags-1) * viadev->fragsize));
table[((frags-1) << 1) + 1] = cpu_to_le32(0x80000000 | /* EOL */
viadev->fragsize);
}
#if 0
printk("%s: size = %d frags = %d fragsize = %d\n", __FUNCTION__, viadev->size, frags, viadev->fragsize);
for (idx=0; idx < frags; idx++)
printk(" address %x, count %x\n", table[idx*2], table[idx*2+1]);
#endif
return 0;
}
/*
......@@ -407,18 +462,28 @@ static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
static inline void snd_via8233_update(via8233_t *chip, viadev_t *viadev)
{
snd_pcm_period_elapsed(viadev->substream);
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
viadev->curidx++;
if (viadev->curidx >= viadev->page_per_frag) {
viadev->curidx = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
}
}
static void snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
via8233_t *chip = snd_magic_cast(via8233_t, dev_id, return);
spin_lock(&chip->reg_lock);
if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->playback);
if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->capture);
spin_unlock(&chip->reg_lock);
}
/*
......@@ -443,12 +508,12 @@ static int snd_via8233_capture_trigger(snd_pcm_substream_t * substream,
static int snd_via8233_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
}
static int snd_via8233_hw_free(snd_pcm_substream_t * substream)
{
return snd_pcm_lib_free_pages(substream);
return 0;
}
static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
......@@ -457,7 +522,6 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_via8233_setup_periods(chip, &chip->playback, substream);
if (chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp;
/* I don't understand this stuff but its from the documentation and this way it works */
......@@ -466,7 +530,7 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
}
return 0;
return snd_via8233_setup_periods(chip, &chip->playback, substream);
}
static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
......@@ -475,10 +539,9 @@ static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
snd_via8233_setup_periods(chip, &chip->capture, substream);
outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
return 0;
return snd_via8233_setup_periods(chip, &chip->capture, substream);
}
static inline unsigned int snd_via8233_cur_ptr(via8233_t *chip, viadev_t *viadev)
......@@ -488,9 +551,14 @@ static inline unsigned int snd_via8233_cur_ptr(via8233_t *chip, viadev_t *viadev
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have this current index register,
* this register makes life easier for us here. */
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->frags;
val *= viadev->fragsize;
val += viadev->fragsize - count;
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
} else {
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
// printk("pointer: ptr = 0x%x, count = 0x%x, val = 0x%x\n", ptr, count, val);
return val;
}
......@@ -522,8 +590,8 @@ static snd_pcm_hardware_t snd_via8233_playback =
buffer_bytes_max: 128 * 1024,
period_bytes_min: 32,
period_bytes_max: 128 * 1024,
periods_min: 1,
periods_max: VIA_MAX_FRAGS,
periods_min: 2,
periods_max: 1024,
fifo_size: 0,
};
......@@ -541,8 +609,8 @@ static snd_pcm_hardware_t snd_via8233_capture =
buffer_bytes_max: 128 * 1024,
period_bytes_min: 32,
period_bytes_max: 128 * 1024,
periods_min: 1,
periods_max: VIA_MAX_FRAGS,
periods_min: 2,
periods_max: 1024,
fifo_size: 0,
};
......@@ -569,8 +637,14 @@ static int snd_via8233_playback_open(snd_pcm_substream_t * substream)
runtime->hw.rates = chip->ac97->rates_front_dac;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0;
}
......@@ -586,8 +660,14 @@ static int snd_via8233_capture_open(snd_pcm_substream_t * substream)
runtime->hw.rates = chip->ac97->rates_adc;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
return 0;
}
......@@ -596,6 +676,8 @@ static int snd_via8233_playback_close(snd_pcm_substream_t * substream)
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->playback);
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL;
/* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
......@@ -607,6 +689,8 @@ static int snd_via8233_capture_close(snd_pcm_substream_t * substream)
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->capture);
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL;
/* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
......@@ -622,6 +706,9 @@ static snd_pcm_ops_t snd_via8233_playback_ops = {
prepare: snd_via8233_playback_prepare,
trigger: snd_via8233_playback_trigger,
pointer: snd_via8233_playback_pointer,
copy: snd_pcm_sgbuf_ops_copy_playback,
silence: snd_pcm_sgbuf_ops_silence,
page: snd_pcm_sgbuf_ops_page,
};
static snd_pcm_ops_t snd_via8233_capture_ops = {
......@@ -633,13 +720,15 @@ static snd_pcm_ops_t snd_via8233_capture_ops = {
prepare: snd_via8233_capture_prepare,
trigger: snd_via8233_capture_trigger,
pointer: snd_via8233_capture_pointer,
copy: snd_pcm_sgbuf_ops_copy_capture,
silence: snd_pcm_sgbuf_ops_silence,
page: snd_pcm_sgbuf_ops_page,
};
static void snd_via8233_pcm_free(snd_pcm_t *pcm)
{
via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return);
chip->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** rpcm)
......@@ -662,8 +751,6 @@ static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** r
strcpy(pcm->name, "VIA 8233");
chip->pcm = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
if (rpcm)
*rpcm = NULL;
return 0;
......@@ -758,14 +845,8 @@ static int snd_via8233_free(via8233_t *chip)
snd_via8233_channel_reset(chip, &chip->playback);
snd_via8233_channel_reset(chip, &chip->capture);
/* --- */
synchronize_irq(chip->irq);
__end_hw:
if (chip->irq)
synchronize_irq(chip->irq);
if (chip->tables)
snd_free_pci_pages(chip->pci,
VIA_NUM_OF_DMA_CHANNELS * sizeof(unsigned int) * VIA_MAX_FRAGS * 2,
chip->tables,
chip->tables_addr);
if (chip->res_port) {
release_resource(chip->res_port);
kfree_nocheck(chip->res_port);
......@@ -831,21 +912,6 @@ static int __devinit snd_via8233_create(snd_card_t * card,
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
/* allocate buffer descriptor lists */
/* the start of each lists must be aligned to 8 bytes */
chip->tables = (unsigned int *)snd_malloc_pci_pages(pci,
VIA_NUM_OF_DMA_CHANNELS * sizeof(unsigned int) * VIA_MAX_FRAGS * 2,
&chip->tables_addr);
if (chip->tables == NULL) {
snd_via8233_free(chip);
return -ENOMEM;
}
/* tables must be aligned to 8 bytes, but the kernel pages
are much bigger, so we don't care */
chip->playback.table = chip->tables;
chip->playback.table_addr = chip->tables_addr;
chip->capture.table = chip->playback.table + VIA_MAX_FRAGS * 2;
chip->capture.table_addr = chip->playback.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
if ((err = snd_via8233_chip_init(chip)) < 0) {
snd_via8233_free(chip);
return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment