/* * Routines for HAL2 soundcards * Copyright (c) by Ulf Carlsson <ulfc@thepuffingroup.com> * * * 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 * */ #define SNDRV_MAIN_OBJECT_FILE #include <sound/driver.h> #include <sound/hal2.h> #include <sound/control.h> #include <asm/sgi/sgihpc.h> #include <asm/addrspace.h> MODULE_AUTHOR("Ulf Carlsson <ulfc@thepuffingroup.com>"); MODULE_DESCRIPTION("Routines for HAL2 soundcards"); MODULE_LICENSE("GPL"); #undef SNDRV_HAL2_DEBUG #define H2_INDIRECT_WAIT(regs) while(regs->isr & H2_ISR_TSTATUS); #define H2_READ_ADDR(addr) (addr | (1<<7)) #define H2_WRITE_ADDR(addr) (addr) inline void snd_hal2_isr_write(snd_hal2_card_t *hal2, unsigned short val) { hal2->hal2.ctl_regs->isr = val; } inline unsigned short snd_hal2_isr_look(snd_hal2_card_t *hal2) { return hal2->hal2.ctl_regs->isr; } inline unsigned short snd_hal2_rev_look(snd_hal2_card_t *hal2) { return hal2->hal2.ctl_regs->rev; } unsigned short snd_hal2_i_look16(snd_hal2_card_t *hal2, unsigned short addr) { snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); return (regs->idr0 & 0xffff); } unsigned long snd_hal2_i_look32(snd_hal2_card_t *hal2, unsigned short addr) { unsigned long ret; snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); ret = regs->idr0 & 0xffff; regs->iar = H2_READ_ADDR(addr | 0x1); H2_INDIRECT_WAIT(regs); ret |= (regs->idr0 & 0xffff) << 16; return ret; } void snd_hal2_i_write16(snd_hal2_card_t *hal2, unsigned short addr, unsigned short val) { snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->idr0 = val; regs->idr1 = 0; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } void snd_hal2_i_write32(snd_hal2_card_t *hal2, unsigned short addr, unsigned long val) { snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->idr0 = val & 0xffff; regs->idr1 = val >> 16; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } static void snd_hal2_i_setbit16(snd_hal2_card_t *hal2, unsigned short addr, unsigned short bit) { snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); regs->idr0 = regs->idr0 | bit; regs->idr1 = 0; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } #if 0 static void snd_hal2_i_setbit32(snd_hal2_card_t *hal2, unsigned short addr, unsigned long bit) { unsigned long tmp; snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); tmp = regs->idr0 | (regs->idr1 << 16) | bit; regs->idr0 = tmp & 0xffff; regs->idr1 = tmp >> 16; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } #endif static void snd_hal2_i_clearbit16(snd_hal2_card_t *hal2, unsigned short addr, unsigned short bit) { snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); regs->idr0 = regs->idr0 & ~bit; regs->idr1 = 0; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } #if 0 static void snd_hal2_i_clearbit32(snd_hal2_card_t *hal2, unsigned short addr, unsigned long bit) { unsigned long tmp; snd_hal2_ctl_regs_t *regs = hal2->hal2.ctl_regs; regs->iar = H2_READ_ADDR(addr); H2_INDIRECT_WAIT(regs); tmp = (regs->idr0 | (regs->idr1 << 16)) & ~bit; regs->idr0 = tmp & 0xffff; regs->idr1 = tmp >> 16; regs->idr2 = 0; regs->idr3 = 0; regs->iar = H2_WRITE_ADDR(addr); H2_INDIRECT_WAIT(regs); } #endif void snd_hal2_dump_regs(snd_hal2_card_t *hal2) { printk("isr: %08hx ", snd_hal2_isr_look(hal2)); printk("rev: %08hx\n", snd_hal2_rev_look(hal2)); printk("relay: %04hx\n", snd_hal2_i_look16(hal2, H2I_RELAY_C)); printk("port en: %04hx ", snd_hal2_i_look16(hal2, H2I_DMA_PORT_EN)); printk("dma end: %04hx ", snd_hal2_i_look16(hal2, H2I_DMA_END)); printk("dma drv: %04hx\n", snd_hal2_i_look16(hal2, H2I_DMA_DRV)); printk("syn ctl: %04hx ", snd_hal2_i_look16(hal2, H2I_SYNTH_C)); printk("aesrx ctl: %04hx ", snd_hal2_i_look16(hal2, H2I_AESRX_C)); printk("aestx ctl: %04hx ", snd_hal2_i_look16(hal2, H2I_AESTX_C)); printk("dac ctl1: %04hx ", snd_hal2_i_look16(hal2, H2I_DAC_C1)); printk("dac ctl2: %08lx ", snd_hal2_i_look32(hal2, H2I_DAC_C2)); printk("adc ctl1: %04hx ", snd_hal2_i_look16(hal2, H2I_ADC_C1)); printk("adc ctl2: %08lx ", snd_hal2_i_look32(hal2, H2I_ADC_C2)); printk("syn map: %04hx\n", snd_hal2_i_look16(hal2, H2I_SYNTH_MAP_C)); printk("bres1 ctl1: %04hx ", snd_hal2_i_look16(hal2, H2I_BRES1_C1)); printk("bres1 ctl2: %04lx ", snd_hal2_i_look32(hal2, H2I_BRES1_C2)); printk("bres2 ctl1: %04hx ", snd_hal2_i_look16(hal2, H2I_BRES2_C1)); printk("bres2 ctl2: %04lx ", snd_hal2_i_look32(hal2, H2I_BRES2_C2)); printk("bres3 ctl1: %04hx ", snd_hal2_i_look16(hal2, H2I_BRES3_C1)); printk("bres3 ctl2: %04lx\n", snd_hal2_i_look32(hal2, H2I_BRES3_C2)); } static int snd_hal2_compute_rate(snd_hal2_card_t *hal2, unsigned int rate) { /* We default to 44.1 kHz and if it isn't possible to fall back to * 48.0 kHz with the needed adjustments of real_rate. */ #ifdef SNDRV_HAL2_DEBUG snd_printk("rate: %d\n", rate); #endif if (rate < 1) rate = 1; /* this is fixed later.. */ /* Note: This is NOT the way they set up the bresenham clock generators * in the specification. I've tried to implement that method but it * doesn't work. It's probably another silly bug in the spec. * * I accidently discovered this method while I was testing and it seems * to work very well with all frequencies, and thee shall follow rule #1 * of programming :-) */ if (44100 % rate == 0) { unsigned short inc; inc = 44100 / rate; hal2->hal2.master = 44100; hal2->hal2.inc = inc; hal2->hal2.mod = 1; } else { unsigned short inc; inc = 48000 / rate; if (inc < 1) inc = 1; rate = 48000 / inc; hal2->hal2.master = 48000; hal2->hal2.inc = inc; hal2->hal2.mod = 1; } #ifdef SNDRV_HAL2_DEBUG snd_printk("real_rate: %d\n", rate); #endif return rate; } static void snd_hal2_set_rate(snd_hal2_card_t *hal2) { unsigned int master = hal2->hal2.master; int inc = hal2->hal2.inc; int mod = hal2->hal2.mod; #ifdef SNDRV_HAL2_DEBUG snd_printk("master: %d inc: %d mod: %d\n", master, inc, mod); #endif snd_hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0); snd_hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (mod - inc - 1)) << 16) | 1); } void snd_hal2_interrupt(snd_hal2_card_t *hal2) { snd_pcm1_substream_t *substream1; if (hal2 && hal2->pcm) { if (hal2->hal2.dac.pbus.pbus && hal2->hal2.dac.pbus.pbus->pbdma_ctrl & 0x01) { substream1 = (snd_pcm1_substream_t *) hal2->playback_substream1; if (substream1 && substream1->ack) substream1->ack(hal2->playback_substream); } if (hal2->hal2.adc.pbus.pbus && hal2->hal2.adc.pbus.pbus->pbdma_ctrl & 0x01) { substream1 = (snd_pcm1_substream_t *) hal2->capture_substream1; if (substream1 && substream1->ack) substream1->ack(hal2->capture_substream); } } } static int snd_hal2_playback_ioctl(void *private_data, struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; snd_pcm1_substream_t *substream1 = (snd_pcm1_substream_t *) substream->private_data; switch (cmd) { case SNDRV_PCM1_IOCTL_RATE: substream1->real_rate = snd_hal2_compute_rate(hal2, substream1->rate); return 0; } return -ENXIO; } static int snd_hal2_capture_ioctl(void *private_data, struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; snd_pcm1_substream_t *substream1 = (snd_pcm1_substream_t *) substream->private_data; switch (cmd) { case SNDRV_PCM1_IOCTL_RATE: substream1->real_rate = snd_hal2_compute_rate(hal2, substream1->rate); return 0; } return -ENXIO; } static int snd_hal2_playback_open(void *private_data, struct snd_pcm_substream *substream) { int err; snd_hal2_card_t *hal2; snd_hal2_pbus_t *pbus; hal2 = (snd_hal2_card_t *) private_data; hal2->playback_substream = substream; hal2->playback_substream1 = (snd_pcm1_substream_t *) substream->private_data; /* Maybe we shouldn't allocate the dma here, but when the driver is * loaded so that we can *beep*. */ if ((err = snd_pcm1_dma_alloc(substream, hal2->hal2.dac.dmaptr, "HAL2 PCM - playback")) < 0) return err; pbus = &hal2->hal2.dac.pbus; pbus->pbusnr = 1; pbus->pbus = &hpc3c0->pbdma[pbus->pbusnr]; #ifdef SNDRV_HAL2_DEBUG snd_printk("playback open ok!\n"); #endif hal2->usecount++; return 0; } static int snd_hal2_capture_open(void *private_data, struct snd_pcm_substream *substream) { int err; snd_hal2_card_t *hal2; snd_hal2_pbus_t *pbus; hal2 = (snd_hal2_card_t *) private_data; hal2->capture_substream = substream; hal2->capture_substream1 = (snd_pcm1_substream_t *) substream->private_data; if ((err = snd_pcm1_dma_alloc(substream, hal2->hal2.adc.dmaptr, "HAL2 PCM - playback")) < 0) return err; pbus = &hal2->hal2.adc.pbus; pbus->pbusnr = 2; pbus->pbus = &hpc3c0->pbdma[pbus->pbusnr]; #ifdef SNDRV_HAL2_DEBUG snd_printk("capture open ok!\n"); #endif hal2->usecount++; return 0; } static void snd_hal2_playback_close(void *private_data, struct snd_pcm_substream *substream) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; if (hal2->hal2.dac.ringbuf) { snd_free_pages((char *) hal2->hal2.dac.ringbuf, hal2->hal2.dac.blocks * sizeof(snd_hal2_ring_t)); hal2->hal2.dac.ringbuf = NULL; } snd_pcm1_dma_free(substream); #ifdef SNDRV_HAL2_DEBUG snd_printk("playback close ok!\n"); #endif hal2->usecount--; } static void snd_hal2_capture_close(void *private_data, struct snd_pcm_substream *substream) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; if (hal2->hal2.adc.ringbuf) { snd_free_pages((char *) hal2->hal2.adc.ringbuf, hal2->hal2.adc.blocks * sizeof(snd_hal2_ring_t)); hal2->hal2.adc.ringbuf = NULL; } snd_pcm1_dma_free(substream); #ifdef SNDRV_HAL2_DEBUG snd_printk("capture close ok!\n"); #endif hal2->usecount--; } #if 0 static void snd_hal2_pio_memset(void *s, int c, size_t n) { snd_hal2_reg_t *reg; reg = (snd_hal2_reg_t *) (s + n); while ((void *) reg-- > s) *reg = c; } #endif static void snd_hal2_playback_prepare(void *private_data, struct snd_pcm_substream *substream, unsigned char *buffer, unsigned int size, unsigned int offset, unsigned int count) { int blocks, block_size; int sample_size; int i; int pg; snd_hal2_ring_t *ring; snd_hal2_pbus_t *pbus; snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; snd_pcm1_substream_t *substream1 = (snd_pcm1_substream_t *) substream->private_data; #ifdef SNDRV_HAL2_DEBUG snd_printk("playback prepare..\n"); #endif /* Recalculate unsupported values of block and block_size.. */ block_size = substream1->block_size; if (block_size > PAGE_SIZE) block_size = substream1->block_size = PAGE_SIZE; blocks = substream1->blocks = substream1->used_size / block_size; if (blocks > PAGE_SIZE / sizeof(snd_hal2_ring_t)) { snd_printk("too many blocks: %d\n", blocks); return; } #ifdef SNDRV_HAL2_DEBUG snd_printk("DAC: blocks: %d block_size: %d size: %u\n", blocks, block_size, size); #endif if (hal2->hal2.dac.ringbuf) { snd_free_pages((char *) hal2->hal2.dac.ringbuf, hal2->hal2.dac.blocks * sizeof(snd_hal2_ring_t)); } hal2->hal2.dac.ringbuf = (snd_hal2_ring_t *) snd_malloc_pages(blocks * sizeof(snd_hal2_ring_t), &pg, 0); if (hal == NULL2->hal2.dac.ringbuf) { snd_printd("Oops, no memory for DMA descriptors"); return; } hal2->hal2.dac.blocks = blocks; /* Setup the ring of DMA descriptors to point to their parts of the DMA * buffer and to generate interrrupts. */ i = 0; ring = hal2->hal2.dac.ringbuf; ring->desc.pbuf = PHYSADDR(buffer); ring->desc.pnext = PHYSADDR(ring + 1); ring->desc.cntinfo = block_size | HPCDMA_XIE; while (++i < blocks) { ring++; ring->desc.pbuf = PHYSADDR(buffer + i * block_size); ring->desc.pnext = PHYSADDR(ring + 1); ring->desc.cntinfo = block_size | HPCDMA_XIE; } ring->desc.pnext = PHYSADDR(hal2->hal2.dac.ringbuf); /* The PBUS can prolly not read thes stuff when it's in the cache so we * have to flush it back to main memory */ dma_cache_wback_inv((unsigned long) hal2->hal2.dac.ringbuf, blocks * sizeof(snd_hal2_ring_t)); /* Now we set up some PBUS information. The PBUS needs information about * what portion of the fifo it will use. If it's receiving or * transmitting, and finally whether the stream is little endian or big * endian. The information is written later, on the trigger call. */ sample_size = substream1->voices * 2; pbus = &hal2->hal2.dac.pbus; pbus->highwater = (sample_size * 2) >> 1; /* halfwords */ pbus->fifobeg = 0; /* playback is first */ pbus->fifoend = (sample_size * 4) >> 3; /* doublewords */ pbus->ctrl = HPC3_PDMACTRL_RT | ((substream1->mode & SNDRV_PCM1_MODE_BIG) ? 0 : HPC3_PDMACTRL_SEL); #ifdef SNDRV_HAL2_DEBUG snd_printk("DAC: mode: %x voices: %d\n", substream1->mode, substream1->voices); #endif /* We disable everything before we do anything at all */ pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; snd_hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); snd_hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); #if 0 snd_hal2_pio_memset(hal2->hal2.aes_regs, 0, sizeof(snd_hal2_aes_regs_t)); snd_hal2_pio_memset(hal2->hal2.syn_regs, 0, sizeof(snd_hal2_syn_regs_t)); #endif /* Setup the HAL2 for playback */ substream1->real_rate = snd_hal2_compute_rate(hal2, substream1->rate); snd_hal2_set_rate(hal2); snd_hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_DAC_C1_DMA_SHIFT) | (1 << H2I_DAC_C1_CLKID_SHIFT) | (substream1->voices << H2I_DAC_C1_DATAT_SHIFT)); snd_hal2_i_write32(hal2, H2I_DAC_C2, 0); /* disable muting */ /* The spec says that we should write 0x08248844 but that's WRONG. HAL2 * does 8 bit DMA, not 16 bit even if it generates 16 bit audio. */ hpc3c0->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */ } static void snd_hal2_capture_prepare(void *private_data, struct snd_pcm_substream *substream, unsigned char *buffer, unsigned int size, unsigned int offset, unsigned int count) { int blocks, block_size; int sample_size; int i; int pg; snd_hal2_ring_t *ring; snd_hal2_pbus_t *pbus; snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; snd_pcm1_substream_t *substream1 = (snd_pcm1_substream_t *) substream->private_data; if (hal == NULL2) { snd_printk("prepare: no private data?\n"); return; } block_size = substream1->block_size; if (block_size > PAGE_SIZE) block_size = substream1->block_size = PAGE_SIZE; blocks = substream1->blocks = substream1->used_size / block_size; if (blocks > PAGE_SIZE / sizeof(snd_hal2_ring_t)) { snd_printk("too many blocks: %d\n", blocks); return; } #ifdef SNDRV_HAL2_DEBUG snd_printk("ADC: blocks: %d block_size: %d size: %u\n", blocks, block_size, size); #endif if (hal2->hal2.adc.ringbuf) { snd_free_pages((char *) hal2->hal2.adc.ringbuf, hal2->hal2.adc.blocks * sizeof(snd_hal2_ring_t)); } hal2->hal2.adc.ringbuf = (snd_hal2_ring_t *) snd_malloc_pages(blocks * sizeof(snd_hal2_ring_t), &pg, 0); if (hal == NULL2->hal2.adc.ringbuf) { snd_printd("Oops, no memory for DMA descriptors"); return; } hal2->hal2.adc.blocks = blocks; /* Setup the ring of DMA descriptors to point to their parts of the DMA * buffer and to generate interrrupts. */ i = 0; ring = hal2->hal2.adc.ringbuf; ring->desc.pbuf = PHYSADDR(buffer); ring->desc.pnext = PHYSADDR(ring + 1); ring->desc.cntinfo = block_size | HPCDMA_XIE; while (++i < blocks) { ring++; ring->desc.pbuf = PHYSADDR(buffer + i * block_size); ring->desc.pnext = PHYSADDR(ring + 1); ring->desc.cntinfo = block_size | HPCDMA_XIE; } ring->desc.pnext = PHYSADDR(hal2->hal2.adc.ringbuf); /* The PBUS can prolly not read thes stuff when it's in the cache so we * have to flush it back to main memory */ dma_cache_wback_inv((unsigned long) hal2->hal2.adc.ringbuf, blocks * sizeof(snd_hal2_ring_t)); /* Now we set up some PBUS information. The PBUS needs information about * what portion of the fifo it will use. If it's receiving or * transmitting, and finally whether the stream is little endian or big * endian. The information is written later, on the trigger call. */ sample_size = substream1->voices * 2; pbus = &hal2->hal2.adc.pbus; pbus->highwater = (sample_size * 2) >> 1; /* halfwords */ pbus->fifobeg = (4 * 4) >> 3; /* capture is second */ pbus->fifoend = (sample_size * 4) >> 3; /* doublewords */ pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | ((substream1->mode & SNDRV_PCM1_MODE_BIG) ? 0 : HPC3_PDMACTRL_SEL); #ifdef SNDRV_HAL2_DEBUG snd_printk("ADC: mode: %x voices: %d\n", substream1->mode, substream1->voices); #endif /* We disable everything before we do anything at all */ pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; snd_hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); snd_hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); /* Setup the HAL2 for capture */ substream1->real_rate = snd_hal2_compute_rate(hal2, substream1->rate); snd_hal2_set_rate(hal2); snd_hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_ADC_C1_DMA_SHIFT) | (1 << H2I_ADC_C1_CLKID_SHIFT)); snd_hal2_i_write16(hal2, H2I_DAC_C1, (1 << H2I_DAC_C1_CLKID_SHIFT) | (substream1->voices << H2I_DAC_C1_DATAT_SHIFT)); snd_hal2_i_write32(hal2, H2I_ADC_C2, 0); /* disable muting */ /* The spec says that we should write 0x08248844 but that's WRONG. HAL2 * does 8 bit DMA, not 16 bit even if it generates 16 bit audio. */ hpc3c0->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */ } static void snd_hal2_playback_trigger(void *private_data, struct snd_pcm_substream *substream, int up) { snd_hal2_card_t *hal2; snd_hal2_pbus_t *pbus; #ifdef SNDRV_HAL2_DEBUG snd_printk("Trigger %s\n", up ? "up" : "down"); #endif hal2 = (snd_hal2_card_t *) private_data; pbus = &hal2->hal2.dac.pbus; if (up) { unsigned long fifobeg, fifoend, highwater; if (hal == NULL2->hal2.dac.ringbuf) { snd_printd("Oops, there was no ringbuf to trigger!\n"); return; } fifobeg = pbus->fifobeg; fifoend = pbus->fifoend; highwater = pbus->highwater; pbus->pbus->pbdma_dptr = PHYSADDR(hal2->hal2.dac.ringbuf); /* We can not activate the PBUS at the same time as we configure * it. We have to write the configuration bits first and then * write both the configuration bits and the activation bits. * If we do not do so, we might get noise in the DMA stream. */ pbus->ctrl |= ((highwater << 8) | (fifobeg << 16) | (fifoend << 24) | HPC3_PDMACTRL_LD); pbus->pbus->pbdma_ctrl = pbus->ctrl; pbus->ctrl |= (HPC3_PDMACTRL_ACT); pbus->pbus->pbdma_ctrl = pbus->ctrl; #if 0 /* Shouldn't this make difference? It works fine without it.. */ if (substream1->mode & SNDRV_PCM1_MODE_BIG) snd_hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); else snd_hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); #endif snd_hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); snd_hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); #ifdef SNDRV_HAL2_DEBUG snd_hal2_dump_regs(hal2); #endif } else { pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; /* The HAL2 itself may remain enabled safely */ } } static void snd_hal2_capture_trigger(void *private_data, struct snd_pcm_substream *substream, int up) { snd_hal2_card_t *hal2; snd_hal2_pbus_t *pbus; #ifdef SNDRV_HAL2_DEBUG snd_printk("Trigger %s\n", up ? "up" : "down"); #endif hal2 = (snd_hal2_card_t *) private_data; pbus = &hal2->hal2.adc.pbus; if (up) { unsigned long fifobeg, fifoend, highwater; if (hal == NULL2->hal2.adc.ringbuf) { snd_printd("Oops, there was no ringbuf to trigger!\n"); return; } fifobeg = pbus->fifobeg; fifoend = pbus->fifoend; highwater = pbus->highwater; pbus->pbus->pbdma_dptr = PHYSADDR(hal2->hal2.adc.ringbuf); pbus->ctrl |= ((highwater << 8) | (fifobeg << 16) | (fifoend << 24) | HPC3_PDMACTRL_LD); pbus->pbus->pbdma_ctrl = pbus->ctrl; pbus->ctrl |= (HPC3_PDMACTRL_ACT); pbus->pbus->pbdma_ctrl = pbus->ctrl; #if 0 if (substream1->mode & SNDRV_PCM1_MODE_BIG) snd_hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); else snd_hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); #endif snd_hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); snd_hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); } else { pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; /* The HAL2 itself may safely remain enabled */ } } static snd_pcm_uframes_t snd_hal2_playback_pointer(void *private_data, struct snd_pcm_substream *substream, unsigned int used_size) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; return hal2->hal2.dac.pbus.pbus->pbdma_bptr; } static snd_pcm_uframes_t snd_hal2_capture_pointer(void *private_data, struct snd_pcm_substream *substream, unsigned int used_size) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) private_data; return hal2->hal2.adc.pbus.pbus->pbdma_bptr; } static int snd_hal2_playback_dma(void *private_data, struct snd_pcm_substream *substream, unsigned char *buffer, unsigned int offset, unsigned char *user, unsigned int count) { int ret; ret = snd_pcm1_playback_dma(private_data, substream, buffer, offset, user, count); dma_cache_wback_inv((unsigned long) &buffer[offset], count); return ret; } static int snd_hal2_capture_dma(void *private_data, struct snd_pcm_substream *substream, unsigned char *buffer, unsigned int offset, unsigned char *user, unsigned int count) { int ret; dma_cache_inv((unsigned long) &buffer[offset], count); ret = snd_pcm1_capture_dma(private_data, substream, buffer, offset, user, count); return ret; } static int snd_hal2_dma_move(void *private_data, struct snd_pcm_substream *substream, unsigned char *dbuffer, unsigned int dest_offset, unsigned char *sbuffer, unsigned int src_offset, unsigned int count) { int ret; ret = snd_pcm1_dma_move(private_data, substream, dbuffer, dest_offset, sbuffer, src_offset, count); dma_cache_wback_inv((unsigned long) &dbuffer[dest_offset], count); return ret; } static int snd_hal2_playback_dma_neutral(void *private_data, struct snd_pcm_substream *substream, unsigned char *buffer, unsigned int offset, unsigned int count, unsigned char neutral_byte) { int ret; ret = snd_pcm1_playback_dma_neutral(private_data, substream, buffer, offset, count, neutral_byte); dma_cache_wback_inv((unsigned long) &buffer[offset], count); return ret; } struct _snd_pcm1_hardware snd_hal2_playback = { SNDRV_PCM1_HW_16BITONLY | SNDRV_PCM1_HW_AUTODMA, /* flags */ SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, /* formats */ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, /* hardware formats */ 0, 2, /* XXX */ /* minimal fragment */ 4000, /* min. rate */ 48000, /* max. rate */ 2, /* max. voices */ snd_hal2_playback_open, snd_hal2_playback_close, snd_hal2_playback_ioctl, snd_hal2_playback_prepare, snd_hal2_playback_trigger, snd_hal2_playback_pointer, snd_hal2_playback_dma, snd_hal2_dma_move, snd_hal2_playback_dma_neutral }; struct _snd_pcm1_hardware snd_hal2_capture = { SNDRV_PCM1_HW_16BITONLY | SNDRV_PCM1_HW_AUTODMA, /* flags */ SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, /* formats */ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, /* hardware formats */ 0, 2, /* XXX */ /* minimal fragment */ 4000, /* min. rate */ 48000, /* max. rate */ 2, /* max. voices */ snd_hal2_capture_open, snd_hal2_capture_close, snd_hal2_capture_ioctl, snd_hal2_capture_prepare, snd_hal2_capture_trigger, snd_hal2_capture_pointer, snd_hal2_capture_dma, snd_hal2_dma_move, NULL }; static void snd_hal2_free_device(void *ptr) { snd_hal2_card_t *hal2 = (snd_hal2_card_t *) ptr; snd_kfree(hal2); } struct snd_pcm *snd_hal2_new_device(struct snd_card *card, snd_irq_t *irqptr, snd_dma_t *dma1ptr, snd_dma_t *dma2ptr, snd_hal2_ctl_regs_t *ctl_regs, snd_hal2_aes_regs_t *aes_regs, snd_hal2_vol_regs_t *vol_regs, snd_hal2_syn_regs_t *syn_regs) { struct snd_pcm *pcm; snd_pcm1_channel_t *pchn1; snd_hal2_card_t *hal2; pcm = snd_pcm1_new_device(card, "HAL2", 1, 1); if (pcm == NULL) return NULL; hal2 = (snd_hal2_card_t *) snd_kcalloc(sizeof(snd_hal2_card_t), GFP_KERNEL); if (hal2 == NULL) return NULL; hal2->pcm = pcm; hal2->card = card; hal2->hal2.irqptr = irqptr; hal2->hal2.dac.dmaptr = dma1ptr; if (dma2ptr) hal2->hal2.adc.dmaptr = dma2ptr; hal2->hal2.ctl_regs = ctl_regs; hal2->hal2.aes_regs = aes_regs; hal2->hal2.vol_regs = vol_regs; hal2->hal2.syn_regs = syn_regs; card->private_data = hal2; card->private_free = snd_hal2_free_device; pchn1 = (snd_pcm1_channel_t *) pcm->playback.private_data; memcpy(&pchn1->hw, &snd_hal2_playback, sizeof(snd_hal2_playback)); pchn1->private_data = hal2; pchn1 = (snd_pcm1_channel_t *) pcm->capture.private_data; memcpy(&pchn1->hw, &snd_hal2_capture, sizeof(snd_hal2_capture)); pchn1->private_data = hal2; pcm->info_flags = SNDRV_PCM_INFO_CODEC | /* SNDRV_PCM_INFO_MMAP | */ SNDRV_PCM_INFO_PLAYBACK | SNDRV_PCM_INFO_CAPTURE | SNDRV_PCM_INFO_DUPLEX; pcm->private_data = hal2; pcm->private_free = snd_hal2_free_device; strcpy(pcm->name, "HAL2"); return pcm; } /* XXX proc interface? */ EXPORT_SYMBOL(snd_hal2_create); EXPORT_SYMBOL(snd_hal2_free); EXPORT_SYMBOL(snd_hal2_interrupt); EXPORT_SYMBOL(snd_hal2_pcm); static int __init alsa_hal2_init(void) { return 0; } static void __exit alsa_hal2_exit(void) { } module_init(alsa_hal2_init) module_exit(alsa_hal2_exit)