diff options
Diffstat (limited to 'sound/pci/cs5535audio/cs5535audio_pcm.c')
| -rw-r--r-- | sound/pci/cs5535audio/cs5535audio_pcm.c | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 60bb82b2ff4..9c2dc911d8d 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -23,9 +23,7 @@ */ #include <linux/init.h> -#include <linux/slab.h> #include <linux/pci.h> -#include <sound/driver.h> #include <sound/core.h> #include <sound/control.h> #include <sound/initval.h> @@ -43,7 +41,7 @@ static struct snd_pcm_hardware snd_cs5535audio_playback = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START + SNDRV_PCM_INFO_RESUME ), .formats = ( SNDRV_PCM_FMTBIT_S16_LE @@ -70,8 +68,7 @@ static struct snd_pcm_hardware snd_cs5535audio_capture = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_START + SNDRV_PCM_INFO_MMAP_VALID ), .formats = ( SNDRV_PCM_FMTBIT_S16_LE @@ -99,9 +96,10 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_cs5535audio_playback; + runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_FRONT_DAC]; + snd_pcm_limit_hw_rates(runtime); cs5535au->playback_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; @@ -142,7 +140,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, if (dma->periods == periods && dma->period_bytes == period_bytes) return 0; - /* the u32 cast is okay because in snd*create we succesfully told + /* the u32 cast is okay because in snd*create we successfully told pci alloc that we're only 32 bit capable so the uppper will be 0 */ addr = (u32) substream->runtime->dma_addr; desc_addr = (u32) dma->desc_buf.addr; @@ -150,8 +148,8 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, struct cs5535audio_dma_desc *desc = &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[i]; desc->addr = cpu_to_le32(addr); - desc->size = cpu_to_le32(period_bytes); - desc->ctlreserved = cpu_to_le32(PRD_EOP); + desc->size = cpu_to_le16(period_bytes); + desc->ctlreserved = cpu_to_le16(PRD_EOP); desc_addr += sizeof(struct cs5535audio_dma_desc); addr += period_bytes; } @@ -159,10 +157,11 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, lastdesc = &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[periods]; lastdesc->addr = cpu_to_le32((u32) dma->desc_buf.addr); lastdesc->size = 0; - lastdesc->ctlreserved = cpu_to_le32(PRD_JMP); + lastdesc->ctlreserved = cpu_to_le16(PRD_JMP); jmpprd_addr = cpu_to_le32(lastdesc->addr + (sizeof(struct cs5535audio_dma_desc)*periods)); + dma->substream = substream; dma->period_bytes = period_bytes; dma->periods = periods; spin_lock_irq(&cs5535au->reg_lock); @@ -193,6 +192,11 @@ static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au, cs_writel(cs5535au, ACC_BM0_PRD, prd_addr); } +static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au) +{ + return cs_readl(cs5535au, ACC_BM0_PRD); +} + static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au) { return cs_readl(cs5535au, ACC_BM0_PNTR); @@ -219,6 +223,11 @@ static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au, cs_writel(cs5535au, ACC_BM1_PRD, prd_addr); } +static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au) +{ + return cs_readl(cs5535au, ACC_BM1_PRD); +} + static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au) { return cs_readl(cs5535au, ACC_BM1_PNTR); @@ -230,6 +239,7 @@ static void cs5535audio_clear_dma_packets(struct cs5535audio *cs5535au, { snd_dma_free_pages(&dma->desc_buf); dma->desc_buf.area = NULL; + dma->substream = NULL; } static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, @@ -249,6 +259,9 @@ static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, err = cs5535audio_build_dma_packets(cs5535au, dma, substream, params_periods(hw_params), params_period_bytes(hw_params)); + if (!err) + dma->pcm_open_flag = 1; + return err; } @@ -257,6 +270,15 @@ static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream) struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); struct cs5535audio_dma *dma = substream->runtime->private_data; + if (dma->pcm_open_flag) { + if (substream == cs5535au->playback_substream) + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_FRONT_DAC_RATE, 0); + else + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_LR_ADC_RATE, 0); + dma->pcm_open_flag = 0; + } cs5535audio_clear_dma_packets(cs5535au, dma, substream); return snd_pcm_lib_free_pages(substream); } @@ -285,11 +307,17 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: dma->ops->enable_dma(cs5535au); break; + case SNDRV_PCM_TRIGGER_RESUME: + dma->ops->enable_dma(cs5535au); + break; case SNDRV_PCM_TRIGGER_STOP: dma->ops->disable_dma(cs5535au); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + dma->ops->disable_dma(cs5535au); + break; default: - snd_printk(KERN_ERR "unhandled trigger\n"); + dev_err(cs5535au->card->dev, "unhandled trigger\n"); err = -EINVAL; break; } @@ -307,13 +335,13 @@ static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream dma = substream->runtime->private_data; curdma = dma->ops->read_dma_pntr(cs5535au); if (curdma < dma->buf_addr) { - snd_printk(KERN_ERR "curdma=%x < %x bufaddr.\n", + dev_err(cs5535au->card->dev, "curdma=%x < %x bufaddr.\n", curdma, dma->buf_addr); return 0; } curdma -= dma->buf_addr; if (curdma >= dma->buf_bytes) { - snd_printk(KERN_ERR "diff=%x >= %x buf_bytes.\n", + dev_err(cs5535au->card->dev, "diff=%x >= %x buf_bytes.\n", curdma, dma->buf_bytes); return 0; } @@ -327,17 +355,21 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; runtime->hw = snd_cs5535audio_capture; + runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_ADC]; + snd_pcm_limit_hw_rates(runtime); cs5535au->capture_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; + olpc_capture_open(cs5535au->ac97); return 0; } static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream) { + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); + olpc_capture_close(cs5535au->ac97); return 0; } @@ -375,6 +407,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { .enable_dma = cs5535audio_playback_enable_dma, .disable_dma = cs5535audio_playback_disable_dma, .setup_prd = cs5535audio_playback_setup_prd, + .read_prd = cs5535audio_playback_read_prd, .pause_dma = cs5535audio_playback_pause_dma, .read_dma_pntr = cs5535audio_playback_read_dma_pntr, }; @@ -384,11 +417,12 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { .enable_dma = cs5535audio_capture_enable_dma, .disable_dma = cs5535audio_capture_disable_dma, .setup_prd = cs5535audio_capture_setup_prd, + .read_prd = cs5535audio_capture_read_prd, .pause_dma = cs5535audio_capture_pause_dma, .read_dma_pntr = cs5535audio_capture_read_dma_pntr, }; -int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) +int snd_cs5535audio_pcm(struct cs5535audio *cs5535au) { struct snd_pcm *pcm; int err; @@ -413,6 +447,7 @@ int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(cs5535au->pci), 64*1024, 128*1024); + cs5535au->pcm = pcm; return 0; } |
