summaryrefslogtreecommitdiffstats
path: root/drivers/sgi/audio/hal2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sgi/audio/hal2.c')
-rw-r--r--drivers/sgi/audio/hal2.c1296
1 files changed, 0 insertions, 1296 deletions
diff --git a/drivers/sgi/audio/hal2.c b/drivers/sgi/audio/hal2.c
deleted file mode 100644
index 8a61dab50..000000000
--- a/drivers/sgi/audio/hal2.c
+++ /dev/null
@@ -1,1296 +0,0 @@
-/* $Id: hal2.c,v 1.13 1999/02/07 22:18:37 ulfc Exp $
- *
- * drivers/sgi/audio/hal2.c
- *
- * Copyright (C) 1998-1999 Ulf Carlsson (ulfc@bun.falkenberg.se)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/soundcard.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/sgihpc.h>
-
-#include "hal2.h"
-
-#define DEBUG
-
-struct hal2_buffer {
- struct hpc_dma_desc desc;
-
- struct hal2_buffer *next;
- unsigned long buf; /* pointer in KSEG1 address space */
-};
-
-/* As you might know, dma descriptors must be 8 byte aligned, that's why we have
- * them in this special way.
- */
-
-struct hal2_channel {
- struct hal2_buffer *ring;
-
- int pbus;
-
- int bres_mod;
- int bres_master;
-
- int bufs;
- int free_bufs;
-
- unsigned long flags;
-#define H2_CH_LITTLE_END (1<<0)
-#define H2_CH_DAC (1<<1)
-#define H2_CH_STEREO (1<<2)
-#define H2_CH_MASTER (1<<3) /* 0=48.0k 1=44.1k */
-#define H2_CH_PORT_ENBL (1<<4)
-#define H2_CH_PBUS_SETUP (1<<5)
-#define H2_CH_PBUS_ENBL (1<<6)
-
-};
-
-struct hal2_private {
- struct hal2_buffer *dac_head;
- struct hal2_buffer *adc_tail;
-
- int dac_underrun;
-
- unsigned long empty_buf; /* in case of underrun */
-
- struct hal2_channel dac_chan;
- struct hal2_channel adc_chan;
-};
-
-struct sgiaudio_chan {
- int started;
- int rp;
- int wp;
- void *buf;
- int bufsz; /* multiple of PAGE_SIZE */
-
- struct sgiaudio_chan_ops *ops;
-
- struct wait_queue *queue;
-};
-
-struct sgiaudio {
- struct sgiaudio_chan dac;
- struct sgiaudio_chan adc;
-
- void *private; /* for internal hal2 usage .. */
-};
-
-struct sgiaudio_chan_ops {
- int (*init) (struct sgiaudio *);
- int (*stereo) (struct sgiaudio *, int);
- int (*endian) (struct sgiaudio *, int);
- int (*freq) (struct sgiaudio *, double);
- int (*configure) (struct sgiaudio *);
- void (*start) (struct sgiaudio *);
- void (*stop) (struct sgiaudio *);
- void (*free) (struct sgiaudio *);
- void *priv;
-};
-
-#if 0
-#define INDIRECT_WAIT(regs) while(regs->isr & H2_ISR_TSTATUS);
-#endif
-
-#define INDIRECT_WAIT(regs) \
-{ \
- int cnt = 1000; \
- printk("hal2: waiting isr:%04hx ", regs->isr); \
- printk("idr0:%04hx idr1:%04hx idr2:%04hx idr3:%04hx\n", \
- regs->idr0, regs->idr1, regs->idr2, regs->idr3); \
- \
- while(regs->isr & H2_ISR_TSTATUS && --cnt) \
- udelay(5); \
- if (!cnt) \
- printk("hal2: failed waiting for indirect trans.\n"); \
- \
- printk("hal2: finished waiting at cnt:%d isr:%04hx ", \
- cnt, regs->isr); \
- printk("idr0:%04hx idr1:%04hx idr2:%04hx idr3:%04hx\n", \
- regs->idr0, regs->idr1, regs->idr2, regs->idr3); \
-} \
-
-static unsigned short ireg_read(unsigned short address)
-{
- unsigned short tmp;
-
- h2_ctrl->iar = address;
- INDIRECT_WAIT(h2_ctrl)
- tmp = h2_ctrl->idr0;
- return tmp;
-}
-
-static void ireg_write(unsigned short address, unsigned short val)
-{
- h2_ctrl->idr0 = val;
- h2_ctrl->iar = address;
- INDIRECT_WAIT(h2_ctrl)
-}
-
-static void ireg_write2(unsigned short address, unsigned short val0, unsigned
- short val1)
-{
- h2_ctrl->idr0 = val0;
- h2_ctrl->idr1 = val1;
- h2_ctrl->iar = address;
- INDIRECT_WAIT(h2_ctrl)
-}
-
-static void ireg_write4(unsigned short address, unsigned short val0, unsigned
- short val1, unsigned short val2, unsigned short val3)
-{
- h2_ctrl->idr0 = val0;
- h2_ctrl->idr1 = val1;
- h2_ctrl->idr2 = val2;
- h2_ctrl->idr3 = val3;
- h2_ctrl->iar = address;
- INDIRECT_WAIT(h2_ctrl)
-}
-
-static void ireg_setbit(unsigned short write_address, unsigned short
- read_address, int bit)
-{
- int tmp;
-
- h2_ctrl->iar = read_address;
- INDIRECT_WAIT(h2_ctrl);
- tmp = h2_ctrl->idr0;
- h2_ctrl->idr0 = tmp | bit;
- h2_ctrl->iar = write_address;
- INDIRECT_WAIT(h2_ctrl);
-}
-
-static void ireg_clearbit(unsigned short write_address, unsigned short
- read_address, int bit)
-{
- unsigned short tmp;
-
- h2_ctrl->iar = read_address;
- INDIRECT_WAIT(h2_ctrl);
- tmp = h2_ctrl->idr0;
- h2_ctrl->idr0 = tmp & ~bit;
- h2_ctrl->iar = write_address;
- INDIRECT_WAIT(h2_ctrl);
-}
-
-static void hal2_reset(void)
-{
- printk("resetting global isr:%04hx\n", h2_ctrl->isr);
- h2_ctrl->isr = 0; /* reset the card */
- printk("reset done isr:%04hx\n", h2_ctrl->isr);
- h2_ctrl->isr = H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N;
- printk("reactivation done isr:%04hx\n", h2_ctrl->isr);
-}
-
-/* enable/disable a specific PBUS dma channel */
-static __inline__ void sgipbus_enable(unsigned int channel, unsigned long desc)
-{
- struct hpc3_pbus_dmacregs *pbus = &hpc3c0->pbdma0;
-
- pbus[channel].pbdma_dptr = desc;
- pbus[channel].pbdma_ctrl |= HPC3_PDMACTRL_ACT;
-}
-
-static __inline__ void sgipbus_disable(unsigned int channel)
-{
- struct hpc3_pbus_dmacregs *pbus = &hpc3c0->pbdma0;
-
- pbus[channel].pbdma_ctrl &= ~HPC3_PDMACTRL_ACT;
-}
-
-static __inline__ int sgipbus_interrupted(unsigned int channel)
-{
- struct hpc3_pbus_dmacregs *pbus = &hpc3c0->pbdma0;
-
- /* When we read pbdma_ctrl, bit 0 indicates interrupt signal.
- * The interrupt signal is also cleared after read
- */
-
- return (pbus[channel].pbdma_ctrl & 0x01);
-}
-
-static int hal2_probe(void)
-{
- unsigned short board, major, minor;
-
- unsigned short tmp;
-
- hal2_reset();
-
- if (h2_ctrl->rev & H2_REV_AUDIO_PRESENT) {
-
- printk("hal2: there was no device?\n");
- return -ENODEV;
- }
-
- board = (h2_ctrl->rev & H2_REV_BOARD_M) >> 12;
- major = (h2_ctrl->rev & H2_REV_MAJOR_CHIP_M) >> 4;
- minor = (h2_ctrl->rev & H2_REV_MINOR_CHIP_M);
-
- printk("SGI H2 Processor, Revision %i.%i.%i\n",
- board, major, minor);
-
- if (board != 4 || major != 1 || minor != 0) {
- printk("hal2: Other revision than 4.1.0 detected\n");
- printk("hal2: Your card is probably not supported\n");
- }
-
-#ifdef DEBUG
- printk("hal2: checking registers\n");
-#endif
-
- /* check that the indirect registers are working by writing some bogus
- * stuff and then reading it back */
-
- ireg_write(H2IW_DAC_C1, 0x123); /* 16 bit register */
- printk("hal2: wrote #1\n");
- ireg_write2(H2IW_BRES2_C2, 0x132, 0x231); /* 32 bit register */
- printk("hal2: wrote #2\n");
-
- if ((tmp = ireg_read(H2IR_DAC_C1)) != 0x123) {
- printk("hal2: Didn't pass register check #1 (%04hx)\n", tmp);
- return -ENODEV;
- }
- printk("hal2: read #1\n");
- if ((tmp = ireg_read(H2IR_BRES2_C2_0)) != 0x132) {
- printk("hal2: Didn't pass register check #2 (%04hx)\n", tmp);
- return -ENODEV;
- }
- printk("hal2: read #2\n");
- if ((tmp = ireg_read(H2IR_BRES2_C2_1)) != 0x231) {
- printk("hal2: Didn't pass register check #3 (%04hx)\n", tmp);
- return -ENODEV;
- }
- printk("hal2: read #3\n");
-
-#ifdef DEBUG
- printk("hal2: card found\n");
-#endif
-
- return 0;
-}
-
-static int hal2_init(struct sgiaudio *sa)
-{
- static int initialized = 0;
-
- if (initialized) {
- printk("hal2_init: already initialized?\n");
- return 0;
- }
-
- if (!sa->private) {
-#ifdef DEBUG
- printk("hal2: allocating private hal2 pointer\n");
-#endif
- sa->private = kmalloc(sizeof(struct hal2_private), GFP_KERNEL);
- if (!sa->private)
- return -ENOMEM;
- memset(sa->private, 0, sizeof(struct hal2_private));
- }
-
-#ifdef DEBUG
- printk("hal2: resetting chip\n");
-#endif
-
- hal2_reset();
-
- /* setup indigo codec mode */
- h2_ctrl->isr &= ~H2_ISR_CODEC_MODE;
- printk("hal2 init done..\n");
-
- initialized = 1;
-
- return 0;
-}
-
-static int hal2_setup_ring(struct hal2_private *hp, struct hal2_channel *chan)
-{
- struct hal2_buffer *hbuf;
- unsigned long buffer;
- int j = 0;
-
- /* FIXME: Clear up the memory leaks here */
-
- chan->ring = kmalloc(sizeof (struct hal2_buffer), GFP_KERNEL);
- if (!chan->ring)
- return -ENOMEM;
-
- hbuf = chan->ring;
- buffer = get_free_page(GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- hbuf->desc.pbuf = PHYSADDR(buffer);
- hbuf->buf = KSEG1ADDR(buffer);
-
- while (j++ < chan->bufs - 1) {
- hbuf->next = kmalloc(sizeof (struct hal2_buffer), GFP_KERNEL);
- if (!chan->ring)
- return -ENOMEM;
-
- buffer = get_free_page(GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- /* we have to link the physical DMA buffers with phyical
- * addresses first so that the HPC3 knows what to do */
-
- hbuf->desc.pnext = PHYSADDR(buffer);
-
- hbuf = hbuf->next;
- hbuf->buf = KSEG1ADDR(buffer);
- hbuf->desc.pbuf = PHYSADDR(buffer);
- }
-
- hbuf->next = chan->ring;
- hbuf->desc.pnext = chan->ring->desc.pbuf;
-
- return 0;
-}
-
-static int hal2_init_dac(struct sgiaudio *sa)
-{
- struct hal2_private *hp;
- struct hal2_channel *chan;
- int err;
-
- printk("initializing dac\n");
- err = hal2_init(sa);
- if (err)
- return err;
-
- hp = (struct hal2_private *) sa->private;
- chan = &hp->dac_chan;
-
- err = hal2_setup_ring(hp, chan);
- if (err)
- return err;
-
- hp->adc_tail = chan->ring;
-
- return 0;
-}
-
-static int hal2_init_adc(struct sgiaudio *sa)
-{
- struct hal2_private *hp;
- struct hal2_channel *chan;
- int err;
-
- printk("initializing adc\n");
-
- err = hal2_init(sa);
- if (err)
- return err;
-
- hp = (struct hal2_private *) sa->private;
- chan = &hp->dac_chan;
-
- err = hal2_setup_ring(hp, chan);
- if (err)
- return err;
-
- hp->dac_head = chan->ring;
-
- return 0;
-}
-
-static __inline__ int hal2_sample_size(struct hal2_channel *chan)
-{
- return (chan->flags & H2_CH_STEREO ? 4 : 2);
-}
-
-static int hal2_setup_pbus(struct hal2_private *hp, struct hal2_channel *chan)
-{
- struct hpc3_pbus_dmacregs *pbus = &hpc3c0->pbdma0;
- int sample_sz, highwater, fifosize;
- unsigned long flags;
- unsigned long fifobeg, fifoend;
-
- chan->pbus = (chan->flags & H2_CH_DAC) ? 0 : 1;
-
- sample_sz = hal2_sample_size(chan); /* bytes/sample */
-
- /* an audio fifo should be 4 samples long and doubleword aligned,
- highwater should be half the fifo size */
-
- fifosize = (sample_sz * 4) >> 3; /* doublewords */
- highwater = (sample_sz * 2) >> 1; /* halfwords */
-
- /* DAC is always before ADC in our PBUS DMA FIFO. Reserve space for the
- * maximum fifo length, we might change to stereo later if we're in mono
- * now
- */
-
- if (chan->flags & H2_CH_DAC)
- fifobeg = 0;
- else
- fifobeg = (4 * 4) >> 3;
-
- fifoend = fifobeg + fifosize;
-
- flags = HPC3_PDMACTRL_RT |
- (chan->flags & H2_CH_DAC ? 0 : HPC3_PDMACTRL_RCV) |
- (chan->flags & H2_CH_LITTLE_END ? HPC3_PDMACTRL_SEL : 0);
-
- pbus[chan->pbus].pbdma_ctrl = (highwater << 8) | (fifobeg << 16) |
- (fifoend << 24) | flags;
-
- /* Realtime, 16-bit, cycles to spend and more default settings for
- * soundcards, taken directly from the spec. */
- hpc3c0->pbus_dmacfgs[chan->pbus][0] = 0x8248844;
-
- return 0;
-}
-
-static void hal2_update_dac_buf(struct sgiaudio *sa, struct hal2_private *hp)
-{
- int rp = sa->dac.rp;
- int wp = sa->dac.wp;
- int bufsz = sa->dac.bufsz;
- struct hal2_buffer *hbuf = hp->dac_head;
- struct hal2_channel *chan = &hp->dac_chan;
- int left;
- int count = 0;
-
- printk("updating dac buffer!\n");
-
- if (!hbuf) {
- printk("Oops, ADC head wasn't set..\n");
- return;
- }
-
- /* bytes left to read in the fifo */
- left = (wp - rp + bufsz) % bufsz;
-
- if (hp->dac_underrun) {
- if (left < hal2_sample_size(&hp->dac_chan)) {
- /* we're still in underrun... */
- return;
- }
- else {
- /* new enforcements have arrived, go back to normal
- * ring buffer behavior */
- hbuf->desc.pbuf = PHYSADDR(hbuf->buf);
- hbuf->desc.pnext = PHYSADDR(hbuf->next->buf);
-
- hbuf = hbuf->next;
- }
- }
-
- /* oops, a newly discovered underrun .. can this happen? */
- if (left < hal2_sample_size(&hp->dac_chan))
- goto out;
-
- if (chan->free_bufs < 1) {
- printk("Oops, lost DAC buffer count!\n");
- return;
- } else
- chan->free_bufs--;
-
- count = (left>PAGE_SIZE)?PAGE_SIZE:left;
-
- if (rp + count < bufsz)
- memcpy((void *) hbuf->buf, sa->dac.buf + rp, count);
- else {
- /* crosses the buffer boundary */
- int first = bufsz - rp - 1;
-
- memcpy((void *) hbuf->buf, sa->dac.buf + rp, first);
- memcpy((void *) hbuf->buf + first, sa->dac.buf, count - first);
- }
-
- sa->dac.rp = (rp + count) % bufsz;
- hbuf->desc.cntinfo = HPCDMA_XIE | (count & HPCDMA_BCNT);
-
- hbuf = hbuf->next;
-
- wake_up_interruptible(&sa->dac.queue);
-out:
-
- /* was this the last buffer before underrun? */
- if (left - count < hal2_sample_size(&hp->dac_chan)) {
- /* ok, loop the empty buf.. */
- hbuf = hbuf->next;
- hbuf->desc.pnext = hbuf->desc.pbuf = PHYSADDR(hp->empty_buf);
- hbuf->desc.cntinfo = (PAGE_SIZE & HPCDMA_BCNT);
-
- hp->dac_underrun = 1;
- }
- hp->dac_head = hbuf;
-}
-
-static void hal2_update_adc_buf(struct sgiaudio *sa, struct hal2_private *hp)
-{
- int rp = sa->adc.rp;
- int wp = sa->adc.wp;
- int bufsz = sa->adc.bufsz;
- struct hal2_buffer *hbuf = hp->dac_head;
- struct hal2_channel *chan = &hp->dac_chan;
- int left;
- int count;
-
- if (!hbuf) {
- printk("Oops, ADC head wasn't set..\n");
- return;
- }
-
- /* bytes left to write in the fifo */
- left = bufsz - (wp - rp + bufsz) % bufsz;
-
- if (chan->free_bufs >= chan->bufs) {
- printk("Oops, lost ADC buffer count!\n");
- return;
- } else
- chan->free_bufs++;
-
- /* check overrun */
- if (left < PAGE_SIZE)
- return; /* XXX some better way? */
-
- count = PAGE_SIZE;
-
- memcpy(sa->adc.buf + wp, (void *) hbuf->buf, count);
- sa->adc.wp = (wp + count) % bufsz;
-
- wake_up_interruptible(&sa->adc.queue);
-}
-
-static void hal2_reset_adc_ring(struct hal2_private *hp, struct hal2_channel
- *chan)
-{
- struct hal2_buffer *first, *hbuf;
-
- first = chan->ring;
-
- for (hbuf = first; hbuf->next != first; hbuf = hbuf->next)
- hbuf->desc.cntinfo = HPCDMA_XIE;
-}
-
-static void hal2_enable_port(struct hal2_private *hp, struct hal2_channel *chan)
-{
- if (!(chan->flags & H2_CH_PORT_ENBL)) {
- /* pick a dma port */
- ireg_setbit(H2IW_DMA_DRV, H2IR_DMA_DRV, (1 << chan->pbus));
-
- /* activate it! */
- if (chan->flags & H2_CH_DAC)
- ireg_setbit(H2IW_DMA_PORT_EN, H2IR_DMA_PORT_EN,
- H2I_DMA_PORT_EN_CODECTX);
- else
- ireg_setbit(H2IW_DMA_PORT_EN, H2IR_DMA_PORT_EN,
- H2I_DMA_PORT_EN_CODECR);
-
- chan->flags |= H2_CH_PORT_ENBL;
- }
-}
-
-static void hal2_disable_port(struct hal2_private *hp,
- struct hal2_channel *chan)
-{
- if (chan->flags & H2_CH_PORT_ENBL) {
- if (chan->flags & H2_CH_DAC)
- ireg_clearbit(H2IW_DMA_PORT_EN, H2IR_DMA_PORT_EN,
- H2I_DMA_PORT_EN_CODECTX);
- else
- ireg_clearbit(H2IW_DMA_PORT_EN, H2IR_DMA_PORT_EN,
- H2I_DMA_PORT_EN_CODECR);
-
- chan->flags &= ~H2_CH_PORT_ENBL;
- }
-}
-
-/* We have three bresenham clock generators, which we can use independantly.
- *
- * There is one 44.1k and one 48.0k master clock for each of them. We can
- * adjust the inc and the mod values for those clocks, and thus reduce the
- * frequency.
- *
- * freq = master_clock * (inc / mod); where (inc / mod) is a positive fraction
- * in range [0,1]. Inc should always be set to 4 for codecs
- */
-static __inline__ int hal2_calc_mod(int *mod, int master, double freq)
-{
- double master_freq = (master == 0 ? 44800 : 44100);
- int tmp;
-
- tmp = (4.0 * master_freq) / freq;
- if (tmp > 65536 || tmp < 4)
- return -EINVAL;
-
- *mod = tmp;
-
- return 0;
-}
-
-static __inline__ int hal2_calc_freq(double *freq, int master, int mod)
-{
- double master_freq = (master == 0 ? 44800 : 44100);
- double tmp;
-
- tmp = (4.0 * master_freq) / mod;
- if (tmp < 0 || tmp > 48000)
- return -EINVAL;
-
- *freq = tmp;
-
- return 0;
-}
-
-static int hal2_set_freq(struct hal2_channel *chan, double freq)
-{
- int mod;
- int err;
-
- /* Try both 44.1k master and 48.0k master .. */
-
- err = hal2_calc_mod(&mod, 0, freq);
- if (!err) {
- chan->bres_master = 0;
- chan->bres_mod = mod;
- return 0;
- }
-
- err = hal2_calc_mod(&mod, 1, freq);
- if (!err) {
- chan->bres_master = 1;
- chan->bres_mod = mod;
- return 0;
- }
-
- /* We failed to find a matching mod value for either 44.1 master or
- * 48.0k master, try something else..
- */
- return -EINVAL;
-}
-
-
-/* Exploit this little neat gcc extension to build our three functions :) */
-
-#define __BUILD_CONF_BRESN_CLOCK(clock) \
-static void hal2_configure_bres##clock(struct hal2_private *hp, \
- struct hal2_channel *chan) \
-{ \
- int master = chan->bres_master; \
- int mod = chan->bres_mod; \
- int inc = 4; \
- \
- ireg_write(H2IW_BRES##clock##_C1 , master); \
- ireg_write2(H2IW_BRES##clock##_C2 , inc, mod); \
-} \
-
-__BUILD_CONF_BRESN_CLOCK(1)
-__BUILD_CONF_BRESN_CLOCK(2)
-__BUILD_CONF_BRESN_CLOCK(3)
-
-static int hal2_configure_dac(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
- int datatype = ((chan->flags & H2_CH_STEREO)?2:0) << 8;
- int clock = 1 << 3;
-
- /* Let's be sure that the dma port is disabled */
- hal2_disable_port(hp, chan);
-
- hal2_configure_bres1(hp, chan);
-
- if (chan->flags & H2_CH_LITTLE_END)
- ireg_setbit(H2IW_DMA_END, H2IR_DMA_END,
- H2I_DMA_PORT_EN_CODECTX);
- else
- ireg_clearbit(H2IW_DMA_END, H2IR_DMA_END,
- H2I_DMA_PORT_EN_CODECTX);
-
- ireg_write(H2IW_DAC_C1, chan->pbus | clock | datatype);
-
- hal2_setup_pbus(hp, chan);
-
- /* dac ctrl 2? */
-
- /* Enable the dma port (note: we're not starting the PBUS yet) */
- hal2_enable_port(hp, chan);
-
- return 0;
-}
-
-static int hal2_configure_adc(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
- int datatype = ((chan->flags & H2_CH_STEREO)?2:0) << 8;
- int clock = 2 << 3;
-
- hal2_disable_port(hp, chan);
-
- hal2_configure_bres2(hp, chan);
-
- if (chan->flags & H2_CH_LITTLE_END)
- ireg_setbit(H2IW_DMA_END, H2IR_DMA_END, H2I_DMA_PORT_EN_CODECR);
- else
- ireg_clearbit(H2IW_DMA_END, H2IR_DMA_END,
- H2I_DMA_PORT_EN_CODECR);
-
- ireg_write(H2IW_ADC_C1, chan->pbus | clock | datatype);
-
- hal2_setup_pbus(hp, chan);
-
- /* adc ctrl 2? */
-
- /* Enable the dma port (note: we're not starting the PBUS yet) */
- hal2_enable_port(hp, chan);
-
- return 0;
-}
-
-static int hal2_set_dac_stereo(struct sgiaudio *sa, int stereo)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- chan->flags |= H2_CH_STEREO;
-
- return 0;
-}
-
-static int hal2_set_adc_stereo(struct sgiaudio *sa, int stereo)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- chan->flags |= H2_CH_STEREO;
-
- return 0;
-}
-
-static int hal2_set_dac_endian(struct sgiaudio *sa, int little_end)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- if (little_end)
- chan->flags |= H2_CH_LITTLE_END;
- else
- chan->flags &= ~H2_CH_LITTLE_END;
-
- return 0;
-}
-
-static int hal2_set_adc_endian(struct sgiaudio *sa, int little_end)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->adc_chan;
-
- if (little_end)
- chan->flags |= H2_CH_LITTLE_END;
- else
- chan->flags &= ~H2_CH_LITTLE_END;
-
- return 0;
-}
-
-static int hal2_set_dac_freq(struct sgiaudio *sa, double freq)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
- int err;
-
- err = hal2_set_freq(chan, freq);
- if (err)
- return err;
-
- return 0;
-}
-
-static int hal2_set_adc_freq(struct sgiaudio *sa, double freq)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->adc_chan;
- int err;
-
- err = hal2_set_freq(chan, freq);
- if (err)
- return err;
- return 0;
-}
-
-static void hal2_go(struct hal2_channel *chan)
-{
- /* The hal2 *has* to be enabled before we enable PBUS DMA transfers,
- * atleast I say so.. (we need some kind of "order") */
- if (!(chan->flags & H2_CH_PORT_ENBL))
- return;
-
- if (!(chan->flags & H2_CH_PBUS_ENBL)) {
- sgipbus_enable(chan->pbus, PHYSADDR(&chan->ring->desc));
- chan->flags |= H2_CH_PBUS_ENBL;
- }
-#ifdef DEBUG
- else
- printk("Attempt to enable the H2 DMA channel twice\n");
-#endif
-}
-
-static void hal2_stop_pbus(struct hal2_channel *chan)
-{
- if (chan->flags & H2_CH_PBUS_ENBL) {
- sgipbus_enable(chan->pbus, PHYSADDR(&chan->ring->desc));
- chan->flags &= ~H2_CH_PBUS_ENBL;
- }
-#ifdef DEBUG
- else
- printk("Trying to stop already stopped DMA channel\n");
-#endif
-}
-
-static void hal2_start_adc(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->adc_chan;
-
- hal2_reset_adc_ring(hp, chan);
-
- hal2_go(chan);
-}
-
-static void hal2_start_dac(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- /* fill da funky ring buffer */
- while (chan->free_bufs && !hp->dac_underrun)
- hal2_update_dac_buf(sa, hp);
-
- hal2_go(chan);
-}
-
-static void hal2_stop_dac(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- hal2_disable_port(hp, chan);
-
- hal2_stop_pbus(chan);
-}
-
-static void hal2_stop_adc(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->adc_chan;
-
- hal2_disable_port(hp, chan);
-
- hal2_stop_pbus(chan);
-}
-
-static void hal2_free_dac(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->dac_chan;
-
- if (!hp)
- return;
-
- kfree(hp);
-}
-
-static void hal2_free_adc(struct sgiaudio *sa)
-{
- struct hal2_private *hp = (struct hal2_private *) sa->private;
- struct hal2_channel *chan = &hp->adc_chan;
-
- if (!hp)
- return;
-
- kfree(hp);
-}
-
-void hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct sgiaudio *sa = (struct sgiaudio *) dev_id;
- struct hal2_private *hp = (struct hal2_private *) sa->private;
-
- struct hal2_channel *chan;
-
- chan = &hp->dac_chan;
- if ((chan->flags & H2_CH_PBUS_ENBL) && sgipbus_interrupted(chan->pbus))
- while (chan->free_bufs && !hp->dac_underrun)
- hal2_update_dac_buf(sa, hp);
-
- chan = &hp->adc_chan;
- if ((chan->flags & H2_CH_PBUS_ENBL) && sgipbus_interrupted(chan->pbus))
- ;
-}
-
-/*
- * My bogus OSS interface, please excuse my sins..
- */
-
-static struct sgiaudio_chan_ops dac_ops = {
- hal2_init_dac,
- hal2_set_dac_stereo,
- hal2_set_dac_endian,
- hal2_set_dac_freq,
- hal2_configure_dac,
- hal2_start_dac,
- hal2_stop_dac,
- hal2_free_dac,
-};
-
-static struct sgiaudio_chan_ops adc_ops = {
- hal2_init_adc,
- hal2_set_adc_stereo,
- hal2_set_adc_endian,
- hal2_set_adc_freq,
- hal2_configure_adc,
- hal2_start_adc,
- hal2_stop_adc,
- hal2_free_adc,
-};
-
-static ssize_t sgiaudio_dsp_read(struct file *filp,
- char *buf, size_t count, loff_t *ppos)
-{
- return count;
-}
-
-static ssize_t sgiaudio_dsp_write(struct file *filp,
- const char *buf, size_t count, loff_t *ppos)
-{
- struct sgiaudio *sa = (struct sgiaudio *) filp->private_data;
- struct sgiaudio_chan *chan = &sa->dac;
-
- int wp = chan->wp;
- int rp = chan->rp;
- int bufsz = chan->bufsz;
- int left;
-
- unsigned long flags;
-
- printk("attempt to write..\n");
-
- if (count >= bufsz) {
- printk("hal: short write?\n");
- return -EINVAL; /* XXX we should support this, but not yet */
- }
-
- if (!chan->started) {
- printk("configuring dac.\n");
- chan->ops->configure(sa);
- printk("dac configured\n");
- }
-
- save_and_cli(flags);
-
- left = (rp - wp + bufsz) % bufsz - 1;
-
- if (filp->f_flags | O_NONBLOCK) {
- count = count > left ? left : count;
- } else {
- /* assume that the channel is started since we're here */
- while (left < count) {
- printk("oups, overflow, let's sleep..\n");
- interruptible_sleep_on(&chan->queue);
- left = (rp - wp + bufsz) % bufsz - 1;
- }
- }
-
- restore_flags(flags);
-
- printk("copying buffer\n");
-
- if (!access_ok(VERIFY_READ, buf, count))
- return -EFAULT;
-
- if (wp + count < bufsz)
- __copy_from_user(chan->buf + wp, buf, count);
- else {
- /* crosses the buffer boundary */
- int first = bufsz - wp - 1;
-
- __copy_from_user(chan->buf + wp, buf, first);
- __copy_from_user(chan->buf + first, buf, count - first);
- }
-
- chan->wp = (wp + count) % bufsz;
-
- if (!chan->started) {
- printk("starting channel\n");
- chan->ops->start(sa);
- printk("channel started\n");
- sa->dac.started = 1;
- }
-
- return count;
-}
-
-static int sgiaudio_dsp_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-static int sgiaudio_init_dsp(struct sgiaudio *sa, struct sgiaudio_chan *chan,
- struct sgiaudio_chan_ops *ops)
-{
- int err;
-
- chan->ops = ops;
-
- chan->bufsz = 4 * PAGE_SIZE;
- chan->wp = 0;
- chan->rp = 1;
-
- chan->buf = kmalloc(chan->bufsz, GFP_KERNEL);
- if (!chan->buf)
- return -ENOMEM;
-
- err = chan->ops->init(sa);
- if (err)
- goto cleanup;
-
- err = chan->ops->stereo(sa, 0);
- if (err)
- goto cleanup;
-
- err = chan->ops->endian(sa, 0);
- if (err)
- goto cleanup;
-
- err = chan->ops->freq(sa, 8000);
- if (err)
- goto cleanup;
-
- return 0;
-
-cleanup:
- kfree(chan->buf);
- return err;
-}
-
-static int sgiaudio_dsp_open(struct inode *inode, struct file *filp)
-{
- struct sgiaudio *sa = (struct sgiaudio *) filp->private_data;
- struct sgiaudio_chan *dac, *adc;
- int err;
-
- dac = &sa->dac;
- adc = &sa->adc;
-
- if (filp->f_flags & O_RDONLY || filp->f_flags & O_RDWR) {
- printk("opened with read perm\n");
- err = sgiaudio_init_dsp(sa, &sa->adc, &adc_ops);
- if (err)
- return err;
- }
- if (filp->f_flags & O_WRONLY || filp->f_flags & O_RDWR) {
- printk("opened with write perm\n");
- err = sgiaudio_init_dsp(sa, &sa->dac, &dac_ops);
- if (err)
- return err;
- }
-
- MOD_INC_USE_COUNT;
-#ifdef DEBUG
- printk("DSP opened successfully\n");
-#endif
- return 0;
-
-}
-
-static int sgiaudio_dsp_release(struct inode *inode, struct file *filp)
-{
- struct sgiaudio *sa = (struct sgiaudio *) filp->private_data;
- struct sgiaudio_chan *dac, *adc;
-
- printk("in dsp release..\n");
-
- dac = &sa->dac;
- adc = &sa->adc;
-
- if (filp->f_flags & O_RDONLY || filp->f_flags & O_RDWR)
- adc->ops->free(sa);
-
- if (filp->f_flags & O_WRONLY || filp->f_flags & O_RDWR)
- dac->ops->free(sa);
-
- /* we have to call the default release file operation, to free up
- * structures and decrease usage, this is a little workaround .. */
- printk("dispatching release..");
- inode->i_op->default_file_ops->release(inode, filp);
-
- return 0;
-}
-
-struct file_operations sgiaudio_dsp_ops = {
- NULL, /* sgiaudio_dsp_lseek */
- sgiaudio_dsp_read,
- sgiaudio_dsp_write,
- NULL, /* sgiaudio_dsp_readdir */
- NULL, /* sgiaudio_dsp_select */
- sgiaudio_dsp_ioctl,
- NULL, /* sgiaudio_dsp_mmap */
- sgiaudio_dsp_open,
- NULL, /* sgiaudio_dsp_flush */
- sgiaudio_dsp_release,
-};
-
-static int sgiaudio_mixer_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-static int sgiaudio_mixer_open(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-static int sgiaudio_mixer_release(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-struct file_operations sgiaudio_mixer_ops = {
- NULL, /* sgiaudio_mixer_lseek */
- NULL, /* sgiaudio_mixer_read */
- NULL, /* sgiaudio_mixer_write */
- NULL, /* sgiaudio_mixer_readdir */
- NULL, /* sgiaudio_mixer_select */
- sgiaudio_mixer_ioctl,
- NULL, /* sgiaudio_mixer_mmap */
- sgiaudio_mixer_open,
- NULL, /* sgiaudio_mixer_flush */
- sgiaudio_mixer_release,
-};
-
-static int sgiaudio_open(struct inode *inode, struct file *filp)
-{
- static struct sgiaudio *sa;
- int minor = MINOR(inode->i_rdev);
-
- static int initialized = 0;
-
- if (!initialized) {
- sa = kmalloc(sizeof(struct sgiaudio), GFP_KERNEL);
- if (!sa)
- return -ENOMEM;
-
- memset(sa, 0, sizeof(struct sgiaudio));
-
- filp->private_data = (void *) sa;
-
- initialized++;
- }
-
- switch (minor) {
- case 3:
- filp->f_op = &sgiaudio_dsp_ops;
-
- /* dispatch the call to the specific open routine .. */
- return filp->f_op->open(inode, filp);
-
- /* not reached */
- break;
- default:
- return -ENODEV;
-
- /* not reached */
- break;
- }
- return 0;
-}
-
-static int sgiaudio_release(struct inode *inode, struct file *filp)
-{
- struct sgiaudio *sa = (struct sgiaudio *) filp->private_data;
-
- printk("release dispatched!\n");
-
- if (sa)
- kfree(sa);
-
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-static struct file_operations sgiaudio_ops = {
- NULL, /* sgiaudio_lseek */
- NULL, /* sgiaudio_read */
- NULL, /* sgiaudio_write */
- NULL, /* sgiaudio_readdir */
- NULL, /* sgiaudio_select */
- NULL, /* sgiaudio_ioctl */
- NULL, /* sgiaudio_mmap */
- sgiaudio_open,
- NULL, /* sgiaudio_flush */
- sgiaudio_release,
-};
-
-__initfunc(void sgiaudio_init(void))
-{
- int result;
- int err;
-
-
- err = hal2_probe();
- if (err) {
- printk("sgiaudio: unable to find hal2 subsystem\n");
- return;
- }
-
- printk("sgiaudio: initializing\n");
- result = register_chrdev(SOUND_MAJOR, "sound", &sgiaudio_ops);
- if (result < 0) {
- printk("sgiaudio: unable to get major %d", SOUND_MAJOR);
- }
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
- int err;
- int result;
-
- err = hal2_probe();
- if (err) {
- printk("sgiaudio: unable to find hal2 subsystem\n");
- return -ENODEV;
- }
-
- result = register_chrdev(SOUND_MAJOR, "sound", &sgiaudio_ops);
- if (result < 0) {
- printk("sgiaudio: unable to get major %d", SOUND_MAJOR);
- return result;
- }
-
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_chrdev(SOUND_MAJOR, "sound");
-}
-
-#endif