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 @@ ...@@ -152,6 +152,7 @@
typedef struct _snd_ac97 ac97_t; typedef struct _snd_ac97 ac97_t;
struct _snd_ac97 { struct _snd_ac97 {
void (*reset) (ac97_t *ac97);
void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val); void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val);
unsigned short (*read) (ac97_t *ac97, unsigned short reg); unsigned short (*read) (ac97_t *ac97, unsigned short reg);
void (*wait) (ac97_t *ac97); void (*wait) (ac97_t *ac97);
...@@ -178,6 +179,7 @@ struct _snd_ac97 { ...@@ -178,6 +179,7 @@ struct _snd_ac97 {
unsigned int rates_mic_adc; unsigned int rates_mic_adc;
unsigned int spdif_status; unsigned int spdif_status;
unsigned short regs[0x80]; /* register cache */ unsigned short regs[0x80]; /* register cache */
unsigned int limited_regs; /* allow limited registers only */
bitmap_member(reg_accessed,0x80); /* bit flags */ bitmap_member(reg_accessed,0x80); /* bit flags */
union { /* vendor specific code */ union { /* vendor specific code */
struct { struct {
......
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc2" #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) ...@@ -146,20 +146,15 @@ static inline int compare_timestamp_rel(snd_seq_event_t *a, snd_seq_event_t *b)
} }
/* enqueue cell to prioq */ /* 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; snd_seq_event_cell_t *cur, *prev;
unsigned long flags; unsigned long flags;
int count;
int prior; int prior;
if (f == NULL) { snd_assert(f, return -EINVAL);
snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n"); snd_assert(cell, return -EINVAL);
return;
}
if (cell == NULL) {
snd_printd("oops: snd_seq_prioq_cell_in() called with NULL cell\n");
return;
}
/* check flags */ /* check flags */
prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK); 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) ...@@ -177,7 +172,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
cell->next = NULL; cell->next = NULL;
f->cells++; f->cells++;
spin_unlock_irqrestore(&f->lock, flags); spin_unlock_irqrestore(&f->lock, flags);
return; return 0;
} }
} }
/* traverse list of elements to find the place where the new cell is /* 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) ...@@ -186,6 +181,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
prev = NULL; /* previous cell */ prev = NULL; /* previous cell */
cur = f->head; /* cursor */ cur = f->head; /* cursor */
count = 10000; /* FIXME: enough big, isn't it? */
while (cur != NULL) { while (cur != NULL) {
/* compare timestamps */ /* compare timestamps */
int rel = compare_timestamp_rel(&cell->event, &cur->event); 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) ...@@ -199,6 +195,11 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
/* move cursor to next cell */ /* move cursor to next cell */
prev = cur; prev = cur;
cur = cur->next; 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 */ /* insert it before cursor */
...@@ -212,6 +213,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell) ...@@ -212,6 +213,7 @@ void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
f->tail = cell; f->tail = cell;
f->cells++; f->cells++;
spin_unlock_irqrestore(&f->lock, flags); spin_unlock_irqrestore(&f->lock, flags);
return 0;
} }
/* dequeue cell from prioq */ /* dequeue cell from prioq */
......
...@@ -41,7 +41,7 @@ extern prioq_t *snd_seq_prioq_new(void); ...@@ -41,7 +41,7 @@ extern prioq_t *snd_seq_prioq_new(void);
extern void snd_seq_prioq_delete(prioq_t **fifo); extern void snd_seq_prioq_delete(prioq_t **fifo);
/* enqueue cell to prioq */ /* 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 */ /* dequeue cell from prioq */
extern snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t *f); 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) ...@@ -365,9 +365,11 @@ void snd_seq_timer_continue(seq_timer_t * tmr)
return; return;
if (tmr->running) if (tmr->running)
return; return;
if (! tmr->initialized) if (! tmr->initialized) {
snd_seq_timer_reset(tmr);
if (initialize_timer(tmr) < 0) if (initialize_timer(tmr) < 0)
return; return;
}
snd_timer_start(tmr->timeri, tmr->ticks); snd_timer_start(tmr->timeri, tmr->ticks);
tmr->running = 1; tmr->running = 1;
do_gettimeofday(&tmr->last_update); do_gettimeofday(&tmr->last_update);
......
...@@ -168,7 +168,7 @@ static int __init snd_card_dt019x_isapnp(int dev, struct snd_card_dt019x *acard) ...@@ -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_dma8[dev] = pdev->dma_resource[0].start;
snd_irq[dev] = pdev->irq_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_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; pdev = acard->devmpu;
if (!pdev || pdev->prepare(pdev)<0) if (!pdev || pdev->prepare(pdev)<0)
......
...@@ -91,10 +91,10 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { ...@@ -91,10 +91,10 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819 }, { 0x41445303, 0xffffffff, "AD1819", patch_ad1819 },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881 }, { 0x41445340, 0xffffffff, "AD1881", patch_ad1881 },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881 }, { 0x41445348, 0xffffffff, "AD1881A", patch_ad1881 },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1881 }, { 0x41445360, 0xffffffff, "AD1885", patch_ad1885 },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 }, { 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 }, { 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445372, 0xffffffff, "AD1981A", NULL }, { 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL }, { 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL }, { 0x414c4310, 0xfffffff0, "RL5382", NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL }, { 0x414c4320, 0xfffffff0, "RL5383", NULL },
...@@ -240,12 +240,11 @@ void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value ...@@ -240,12 +240,11 @@ void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value
set_bit(reg, ac97->reg_accessed); 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) 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)) if (!snd_ac97_valid_reg(ac97, reg))
return; return;
spin_lock(&ac97->reg_lock); spin_lock(&ac97->reg_lock);
...@@ -254,8 +253,9 @@ static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned ...@@ -254,8 +253,9 @@ static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned
if (value != ac97->regs[reg]) if (value != ac97->regs[reg])
snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]); snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]);
spin_unlock(&ac97->reg_lock); spin_unlock(&ac97->reg_lock);
}
#endif #endif
snd_ac97_write_cache(ac97, reg, value);
}
int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short 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) ...@@ -911,6 +911,9 @@ static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg)
{ {
unsigned short val, mask = 0x8000; unsigned short val, mask = 0x8000;
if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
return 0;
switch (reg) { switch (reg) {
case AC97_MASTER_TONE: case AC97_MASTER_TONE:
return ac97->caps & 0x04 ? 1 : 0; return ac97->caps & 0x04 ? 1 : 0;
...@@ -1461,6 +1464,12 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) ...@@ -1461,6 +1464,12 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
*ac97 = *_ac97; *ac97 = *_ac97;
ac97->card = card; ac97->card = card;
spin_lock_init(&ac97->reg_lock); 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 */ snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */
if (ac97->wait) if (ac97->wait)
ac97->wait(ac97); ac97->wait(ac97);
...@@ -1499,6 +1508,10 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) ...@@ -1499,6 +1508,10 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
snd_ac97_free(ac97); snd_ac97_free(ac97);
return -EIO; return -EIO;
} }
if (ac97->reset) // FIXME: always skipping?
goto __ready_ok;
/* FIXME: add powerdown control */ /* FIXME: add powerdown control */
/* nothing should be in powerdown mode */ /* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); 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) ...@@ -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); snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates_lfe_dac);
ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC; ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
} }
/* additional initializations */
if (ac97->init) if (ac97->init)
ac97->init(ac97); ac97->init(ac97);
snd_ac97_get_name(ac97, ac97->id, name); snd_ac97_get_name(ac97, ac97->id, name);
...@@ -1738,6 +1752,9 @@ static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffe ...@@ -1738,6 +1752,9 @@ static void snd_ac97_proc_regs_read_main(ac97_t *ac97, snd_info_buffer_t * buffe
int reg, val; int reg, val;
for (reg = 0; reg < 0x80; reg += 2) { for (reg = 0; reg < 0x80; reg += 2) {
if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
val = 0xffff;
else
val = snd_ac97_read(ac97, reg); val = snd_ac97_read(ac97, reg);
snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val); snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val);
} }
...@@ -1903,6 +1920,11 @@ void snd_ac97_resume(ac97_t *ac97) ...@@ -1903,6 +1920,11 @@ void snd_ac97_resume(ac97_t *ac97)
{ {
int i; int i;
if (ac97->reset) {
ac97->reset(ac97);
goto __reset_ready;
}
snd_ac97_write(ac97, AC97_POWERDOWN, 0); snd_ac97_write(ac97, AC97_POWERDOWN, 0);
snd_ac97_write(ac97, AC97_RESET, 0); snd_ac97_write(ac97, AC97_RESET, 0);
udelay(100); udelay(100);
...@@ -1916,6 +1938,7 @@ void snd_ac97_resume(ac97_t *ac97) ...@@ -1916,6 +1938,7 @@ void snd_ac97_resume(ac97_t *ac97)
break; break;
mdelay(1); mdelay(1);
} }
__reset_ready:
if (ac97->init) if (ac97->init)
ac97->init(ac97); ac97->init(ac97);
......
...@@ -300,6 +300,20 @@ int patch_ad1881(ac97_t * ac97) ...@@ -300,6 +300,20 @@ int patch_ad1881(ac97_t * ac97)
return 0; 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) int patch_ad1886(ac97_t * ac97)
{ {
patch_ad1881(ac97); patch_ad1881(ac97);
......
...@@ -35,4 +35,5 @@ int patch_cirrus_spdif(ac97_t * ac97); ...@@ -35,4 +35,5 @@ int patch_cirrus_spdif(ac97_t * ac97);
int patch_conexant(ac97_t * ac97); int patch_conexant(ac97_t * ac97);
int patch_ad1819(ac97_t * ac97); int patch_ad1819(ac97_t * ac97);
int patch_ad1881(ac97_t * ac97); int patch_ad1881(ac97_t * ac97);
int patch_ad1885(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97); int patch_ad1886(ac97_t * ac97);
...@@ -1970,9 +1970,10 @@ static void snd_ali_resume(struct pci_dev *dev) ...@@ -1970,9 +1970,10 @@ static void snd_ali_resume(struct pci_dev *dev)
static int snd_ali_free(ali_t * codec) static int snd_ali_free(ali_t * codec)
{ {
snd_ali_disable_address_interrupt(codec); snd_ali_disable_address_interrupt(codec);
if (codec->irq >= 0) {
synchronize_irq(codec->irq); synchronize_irq(codec->irq);
if (codec->irq >=0)
free_irq(codec->irq, (void *)codec); free_irq(codec->irq, (void *)codec);
}
if (codec->res_port) { if (codec->res_port) {
release_resource(codec->res_port); release_resource(codec->res_port);
kfree_nocheck(codec->res_port); kfree_nocheck(codec->res_port);
......
...@@ -1300,7 +1300,7 @@ static int snd_cs4281_free(cs4281_t *chip) ...@@ -1300,7 +1300,7 @@ static int snd_cs4281_free(cs4281_t *chip)
} }
#endif #endif
snd_cs4281_proc_done(chip); snd_cs4281_proc_done(chip);
if(chip->irq >= 0) if (chip->irq >= 0)
synchronize_irq(chip->irq); synchronize_irq(chip->irq);
/* Mask interrupts */ /* Mask interrupts */
......
...@@ -64,7 +64,7 @@ static void mpu401_clear_rx(emu10k1_t *emu, emu10k1_midi_t *mpu) ...@@ -64,7 +64,7 @@ static void mpu401_clear_rx(emu10k1_t *emu, emu10k1_midi_t *mpu)
mpu401_read_data(emu, mpu); mpu401_read_data(emu, mpu);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (timeout <= 0) 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 #endif
} }
...@@ -143,7 +143,7 @@ static void snd_emu10k1_midi_cmd(emu10k1_t * emu, emu10k1_midi_t *midi, unsigned ...@@ -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); spin_unlock_irqrestore(&midi->input_lock, flags);
if (!ok) 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, cmd, emu->port,
mpu401_read_stat(emu, midi), mpu401_read_stat(emu, midi),
mpu401_read_data(emu, midi)); mpu401_read_data(emu, midi));
......
...@@ -968,11 +968,13 @@ static void snd_emu10k1_pcm_free(snd_pcm_t *pcm) ...@@ -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); emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return);
emu->pcm = NULL; 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) int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
{ {
snd_pcm_t *pcm; snd_pcm_t *pcm;
snd_pcm_substream_t *substream;
int err; int err;
if (rpcm) if (rpcm)
...@@ -992,6 +994,10 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) ...@@ -992,6 +994,10 @@ int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
strcpy(pcm->name, "EMU10K1"); strcpy(pcm->name, "EMU10K1");
emu->pcm = pcm; 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) if (rpcm)
*rpcm = pcm; *rpcm = pcm;
......
...@@ -1532,7 +1532,6 @@ static int snd_ensoniq_free(ensoniq_t *ensoniq) ...@@ -1532,7 +1532,6 @@ static int snd_ensoniq_free(ensoniq_t *ensoniq)
outl(0, ES_REG(ensoniq, CONTROL)); /* switch everything off */ outl(0, ES_REG(ensoniq, CONTROL)); /* switch everything off */
outl(0, ES_REG(ensoniq, SERIAL)); /* clear serial interface */ outl(0, ES_REG(ensoniq, SERIAL)); /* clear serial interface */
#endif #endif
if(ensoniq->irq >= 0)
synchronize_irq(ensoniq->irq); synchronize_irq(ensoniq->irq);
pci_set_power_state(ensoniq->pci, 3); pci_set_power_state(ensoniq->pci, 3);
__hw_end: __hw_end:
......
...@@ -4072,7 +4072,7 @@ static int snd_ice1712_free(ice1712_t *ice) ...@@ -4072,7 +4072,7 @@ static int snd_ice1712_free(ice1712_t *ice)
/* --- */ /* --- */
__hw_end: __hw_end:
snd_ice1712_proc_done(ice); snd_ice1712_proc_done(ice);
if (ice->irq) { if (ice->irq >= 0) {
synchronize_irq(ice->irq); synchronize_irq(ice->irq);
free_irq(ice->irq, (void *) ice); free_irq(ice->irq, (void *) ice);
} }
...@@ -4146,7 +4146,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, ...@@ -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, 0x40, 0x807f);
pci_write_config_word(ice->pci, 0x42, 0x0006); pci_write_config_word(ice->pci, 0x42, 0x0006);
snd_ice1712_proc_init(ice); 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) { if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
snd_ice1712_free(ice); snd_ice1712_free(ice);
......
...@@ -1104,7 +1104,6 @@ static int snd_intel8x0_free(intel8x0_t *chip) ...@@ -1104,7 +1104,6 @@ static int snd_intel8x0_free(intel8x0_t *chip)
outb(ICH_RESETREGS, ICHREG(chip, PO_CR)); outb(ICH_RESETREGS, ICHREG(chip, PO_CR));
outb(ICH_RESETREGS, ICHREG(chip, MC_CR)); outb(ICH_RESETREGS, ICHREG(chip, MC_CR));
/* --- */ /* --- */
if(chip->irq >= 0)
synchronize_irq(chip->irq); synchronize_irq(chip->irq);
__hw_end: __hw_end:
if (chip->bdbars) if (chip->bdbars)
......
...@@ -2310,7 +2310,7 @@ static int snd_m3_free(m3_t *chip) ...@@ -2310,7 +2310,7 @@ static int snd_m3_free(m3_t *chip)
vfree(chip->suspend_mem); vfree(chip->suspend_mem);
#endif #endif
if(chip->irq >= 0) if (chip->irq >= 0)
synchronize_irq(chip->irq); synchronize_irq(chip->irq);
if (chip->iobase_res) { if (chip->iobase_res) {
......
...@@ -892,7 +892,7 @@ static snd_pcm_ops_t snd_nm256_capture_ops = { ...@@ -892,7 +892,7 @@ static snd_pcm_ops_t snd_nm256_capture_ops = {
#endif #endif
}; };
static int __init static int __devinit
snd_nm256_pcm(nm256_t *chip, int device) snd_nm256_pcm(nm256_t *chip, int device)
{ {
snd_pcm_t *pcm; snd_pcm_t *pcm;
...@@ -1188,21 +1188,31 @@ snd_nm256_ac97_reset(ac97_t *ac97) ...@@ -1188,21 +1188,31 @@ snd_nm256_ac97_reset(ac97_t *ac97)
} }
/* create an ac97 mixer interface */ /* create an ac97 mixer interface */
static int __init static int __devinit
snd_nm256_mixer(nm256_t *chip) snd_nm256_mixer(nm256_t *chip)
{ {
ac97_t ac97; 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)); memset(&ac97, 0, sizeof(ac97));
ac97.init = snd_nm256_ac97_reset; ac97.reset = snd_nm256_ac97_reset;
ac97.write = snd_nm256_ac97_write; ac97.write = snd_nm256_ac97_write;
ac97.read = snd_nm256_ac97_read; 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; ac97.private_data = chip;
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) return snd_ac97_mixer(chip->card, &ac97, &chip->ac97);
return err;
return 0;
} }
/* /*
...@@ -1211,7 +1221,7 @@ snd_nm256_mixer(nm256_t *chip) ...@@ -1211,7 +1221,7 @@ snd_nm256_mixer(nm256_t *chip)
* RAM. * RAM.
*/ */
static int __init static int __devinit
snd_nm256_peek_for_sig(nm256_t *chip) snd_nm256_peek_for_sig(nm256_t *chip)
{ {
/* The signature is located 1K below the end of video RAM. */ /* The signature is located 1K below the end of video RAM. */
...@@ -1346,7 +1356,7 @@ static int snd_nm256_free(nm256_t *chip) ...@@ -1346,7 +1356,7 @@ static int snd_nm256_free(nm256_t *chip)
if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
snd_nm256_capture_stop(chip); snd_nm256_capture_stop(chip);
if(chip->irq >= 0) if (chip->irq >= 0)
synchronize_irq(chip->irq); synchronize_irq(chip->irq);
if (chip->cport) if (chip->cport)
...@@ -1374,7 +1384,7 @@ static int snd_nm256_dev_free(snd_device_t *device) ...@@ -1374,7 +1384,7 @@ static int snd_nm256_dev_free(snd_device_t *device)
return snd_nm256_free(chip); return snd_nm256_free(chip);
} }
static int __init static int __devinit
snd_nm256_create(snd_card_t *card, struct pci_dev *pci, snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
int play_bufsize, int capt_bufsize, int play_bufsize, int capt_bufsize,
int force_load, int force_load,
......
...@@ -238,7 +238,7 @@ struct _snd_via686a { ...@@ -238,7 +238,7 @@ struct _snd_via686a {
snd_card_t *card; snd_card_t *card;
snd_pcm_t *pcm; snd_pcm_t *pcm;
snd_pcm_t *pcm_fm; /*snd_pcm_t *pcm_fm;*/
viadev_t playback; viadev_t playback;
viadev_t capture; viadev_t capture;
/*viadev_t playback_fm;*/ /*viadev_t playback_fm;*/
...@@ -564,8 +564,13 @@ static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev ...@@ -564,8 +564,13 @@ static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev
val = 0; val = 0;
else else
val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries; val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size; val *= viadev->tbl_size;
val += viadev->tbl_size - count; val += viadev->tbl_size - count;
} else {
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
viadev->lastptr = ptr; viadev->lastptr = ptr;
viadev->lastcount = count; viadev->lastcount = count;
// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val); // 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) ...@@ -632,10 +637,10 @@ static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
chip->playback.substream = substream; chip->playback.substream = substream;
runtime->hw = snd_via686a_playback; runtime->hw = snd_via686a_playback;
runtime->hw.rates = chip->ac97->rates_front_dac; 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)) if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000; 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) if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err; return err;
#if 0 #if 0
...@@ -658,10 +663,10 @@ static int snd_via686a_capture_open(snd_pcm_substream_t * substream) ...@@ -658,10 +663,10 @@ static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
chip->capture.substream = substream; chip->capture.substream = substream;
runtime->hw = snd_via686a_capture; runtime->hw = snd_via686a_capture;
runtime->hw.rates = chip->ac97->rates_adc; 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)) if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000; 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) if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err; return err;
#if 0 #if 0
...@@ -1020,7 +1025,7 @@ static int __devinit snd_via686a_create(snd_card_t * card, ...@@ -1020,7 +1025,7 @@ static int __devinit snd_via686a_create(snd_card_t * card,
if (ac97_clock >= 8000 && ac97_clock <= 48000) if (ac97_clock >= 8000 && ac97_clock <= 48000)
chip->ac97_clock = ac97_clock; chip->ac97_clock = ac97_clock;
pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision); pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
synchronize_irq(pci->irq); synchronize_irq(chip->irq);
/* initialize offsets */ /* initialize offsets */
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS; chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_sgbuf.h>
#include <sound/pcm_params.h>
#include <sound/info.h> #include <sound/info.h>
#include <sound/ac97_codec.h> #include <sound/ac97_codec.h>
#include <sound/mpu401.h> #include <sound/mpu401.h>
...@@ -157,11 +159,8 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000"); ...@@ -157,11 +159,8 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA_REG_AC97_DATA_MASK 0xffff #define VIA_REG_AC97_DATA_MASK 0xffff
#define VIA_REG_SGD_SHADOW 0x84 /* dword */ #define VIA_REG_SGD_SHADOW 0x84 /* dword */
/* #define VIA_TBL_BIT_FLAG 0x40000000
* #define VIA_TBL_BIT_EOL 0x80000000
*/
#define VIA_MAX_FRAGS 32
/* /*
* *
...@@ -169,15 +168,78 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000"); ...@@ -169,15 +168,78 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
typedef struct { typedef struct {
unsigned long reg_offset; unsigned long reg_offset;
unsigned int *table;
dma_addr_t table_addr;
snd_pcm_substream_t *substream; snd_pcm_substream_t *substream;
dma_addr_t physbuf; int running;
unsigned int size; unsigned int size;
unsigned int fragsize; unsigned int fragsize;
unsigned int frags; 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; } 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; typedef struct _snd_via8233 via8233_t;
#define chip_t via8233_t #define chip_t via8233_t
...@@ -200,9 +262,6 @@ struct _snd_via8233 { ...@@ -200,9 +262,6 @@ struct _snd_via8233 {
spinlock_t reg_lock; spinlock_t reg_lock;
snd_info_entry_t *proc_entry; snd_info_entry_t *proc_entry;
void *tables;
dma_addr_t tables_addr;
}; };
static struct pci_device_id snd_via8233_ids[] __devinitdata = { 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) ...@@ -323,15 +382,19 @@ static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START; val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START;
viadev->running = 1;
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
val = VIA_REG_CTRL_TERMINATE; val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE; val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE;
viadev->running = 1;
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = VIA_REG_CTRL_INT; val = VIA_REG_CTRL_INT;
viadev->running = 0;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -342,21 +405,33 @@ static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd) ...@@ -342,21 +405,33 @@ static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
return 0; return 0;
} }
static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev, static int snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream) snd_pcm_substream_t *substream)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
int idx, frags;
unsigned int *table = viadev->table;
unsigned long port = chip->port + viadev->reg_offset; 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->size = snd_pcm_lib_buffer_bytes(substream);
viadev->fragsize = snd_pcm_lib_period_bytes(substream); viadev->fragsize = snd_pcm_lib_period_bytes(substream);
viadev->frags = runtime->periods; 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); 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) { if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
unsigned int slots; unsigned int slots;
int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT; 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, ...@@ -378,27 +453,7 @@ static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
0xff000000, /* STOP index is never reached */ 0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX); port + VIA_REG_OFFSET_STOP_IDX);
} }
return 0;
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
} }
/* /*
...@@ -407,18 +462,28 @@ static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev, ...@@ -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) 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); 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) 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); 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)) if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->playback); snd_via8233_update(chip, &chip->playback);
if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG)) if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->capture); 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, ...@@ -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, static int snd_via8233_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params) 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) 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) 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) ...@@ -457,7 +522,6 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); 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) { if (chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp; unsigned int tmp;
/* I don't understand this stuff but its from the documentation and this way it works */ /* 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) ...@@ -466,7 +530,7 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff; tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX)); 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) 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) ...@@ -475,10 +539,9 @@ static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); 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_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO)); 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) 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 ...@@ -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; count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have this current index register, /* The via686a does not have this current index register,
* this register makes life easier for us here. */ * this register makes life easier for us here. */
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->frags; val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
val *= viadev->fragsize; if (val < viadev->tbl_entries - 1) {
val += viadev->fragsize - count; 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); // printk("pointer: ptr = 0x%x, count = 0x%x, val = 0x%x\n", ptr, count, val);
return val; return val;
} }
...@@ -522,8 +590,8 @@ static snd_pcm_hardware_t snd_via8233_playback = ...@@ -522,8 +590,8 @@ static snd_pcm_hardware_t snd_via8233_playback =
buffer_bytes_max: 128 * 1024, buffer_bytes_max: 128 * 1024,
period_bytes_min: 32, period_bytes_min: 32,
period_bytes_max: 128 * 1024, period_bytes_max: 128 * 1024,
periods_min: 1, periods_min: 2,
periods_max: VIA_MAX_FRAGS, periods_max: 1024,
fifo_size: 0, fifo_size: 0,
}; };
...@@ -541,8 +609,8 @@ static snd_pcm_hardware_t snd_via8233_capture = ...@@ -541,8 +609,8 @@ static snd_pcm_hardware_t snd_via8233_capture =
buffer_bytes_max: 128 * 1024, buffer_bytes_max: 128 * 1024,
period_bytes_min: 32, period_bytes_min: 32,
period_bytes_max: 128 * 1024, period_bytes_max: 128 * 1024,
periods_min: 1, periods_min: 2,
periods_max: VIA_MAX_FRAGS, periods_max: 1024,
fifo_size: 0, fifo_size: 0,
}; };
...@@ -569,8 +637,14 @@ static int snd_via8233_playback_open(snd_pcm_substream_t * substream) ...@@ -569,8 +637,14 @@ static int snd_via8233_playback_open(snd_pcm_substream_t * substream)
runtime->hw.rates = chip->ac97->rates_front_dac; runtime->hw.rates = chip->ac97->rates_front_dac;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000)) if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000; 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) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err; return err;
#endif
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0; return 0;
} }
...@@ -586,8 +660,14 @@ static int snd_via8233_capture_open(snd_pcm_substream_t * substream) ...@@ -586,8 +660,14 @@ static int snd_via8233_capture_open(snd_pcm_substream_t * substream)
runtime->hw.rates = chip->ac97->rates_adc; runtime->hw.rates = chip->ac97->rates_adc;
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000)) if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000; 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) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err; return err;
#endif
return 0; return 0;
} }
...@@ -596,6 +676,8 @@ static int snd_via8233_playback_close(snd_pcm_substream_t * substream) ...@@ -596,6 +676,8 @@ static int snd_via8233_playback_close(snd_pcm_substream_t * substream)
via8233_t *chip = snd_pcm_substream_chip(substream); via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->playback); snd_via8233_channel_reset(chip, &chip->playback);
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL; chip->playback.substream = NULL;
/* disable DAC power */ /* disable DAC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200); 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) ...@@ -607,6 +689,8 @@ static int snd_via8233_capture_close(snd_pcm_substream_t * substream)
via8233_t *chip = snd_pcm_substream_chip(substream); via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->capture); snd_via8233_channel_reset(chip, &chip->capture);
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL; chip->capture.substream = NULL;
/* disable ADC power */ /* disable ADC power */
snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100); snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
...@@ -622,6 +706,9 @@ static snd_pcm_ops_t snd_via8233_playback_ops = { ...@@ -622,6 +706,9 @@ static snd_pcm_ops_t snd_via8233_playback_ops = {
prepare: snd_via8233_playback_prepare, prepare: snd_via8233_playback_prepare,
trigger: snd_via8233_playback_trigger, trigger: snd_via8233_playback_trigger,
pointer: snd_via8233_playback_pointer, 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 = { static snd_pcm_ops_t snd_via8233_capture_ops = {
...@@ -633,13 +720,15 @@ 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, prepare: snd_via8233_capture_prepare,
trigger: snd_via8233_capture_trigger, trigger: snd_via8233_capture_trigger,
pointer: snd_via8233_capture_pointer, 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) static void snd_via8233_pcm_free(snd_pcm_t *pcm)
{ {
via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return); via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return);
chip->pcm = NULL; 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) 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 ...@@ -662,8 +751,6 @@ static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** r
strcpy(pcm->name, "VIA 8233"); strcpy(pcm->name, "VIA 8233");
chip->pcm = pcm; chip->pcm = pcm;
snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
if (rpcm) if (rpcm)
*rpcm = NULL; *rpcm = NULL;
return 0; return 0;
...@@ -758,14 +845,8 @@ static int snd_via8233_free(via8233_t *chip) ...@@ -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->playback);
snd_via8233_channel_reset(chip, &chip->capture); snd_via8233_channel_reset(chip, &chip->capture);
/* --- */ /* --- */
__end_hw:
if (chip->irq)
synchronize_irq(chip->irq); synchronize_irq(chip->irq);
if (chip->tables) __end_hw:
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) { if (chip->res_port) {
release_resource(chip->res_port); release_resource(chip->res_port);
kfree_nocheck(chip->res_port); kfree_nocheck(chip->res_port);
...@@ -831,21 +912,6 @@ static int __devinit snd_via8233_create(snd_card_t * card, ...@@ -831,21 +912,6 @@ static int __devinit snd_via8233_create(snd_card_t * card,
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS; 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) { if ((err = snd_via8233_chip_init(chip)) < 0) {
snd_via8233_free(chip); snd_via8233_free(chip);
return err; 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