summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/Config.in4
-rw-r--r--drivers/sgi/Config.in1
-rw-r--r--drivers/sgi/Makefile8
-rw-r--r--drivers/sgi/audio/Makefile34
-rw-r--r--drivers/sgi/audio/hal2.c1296
-rw-r--r--drivers/sgi/audio/hal2.h259
-rw-r--r--drivers/sound/Config.in3
-rw-r--r--drivers/sound/Makefile1
-rw-r--r--drivers/sound/hal2.c1529
-rw-r--r--drivers/sound/hal2.h259
10 files changed, 1799 insertions, 1595 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 89da63706..a81a95013 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -113,7 +113,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_SGI" = "y" ]; then
+ dep_tristate 'SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
+ fi
fi
dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
diff --git a/drivers/sgi/Config.in b/drivers/sgi/Config.in
index c399abeef..2f05afc6d 100644
--- a/drivers/sgi/Config.in
+++ b/drivers/sgi/Config.in
@@ -12,7 +12,6 @@ fi
bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'SGI HAL2 Audio support' CONFIG_SGI_HAL2
tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX
tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
if [ "$CONFIG_SGI_NEWPORT_CONSOLE" = "m" ]; then
diff --git a/drivers/sgi/Makefile b/drivers/sgi/Makefile
index 675e9554f..3de37311c 100644
--- a/drivers/sgi/Makefile
+++ b/drivers/sgi/Makefile
@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS) char audio
-ALL_SUB_DIRS := $(SUB_DIRS) char audio
+MOD_SUB_DIRS := $(SUB_DIRS) char
+ALL_SUB_DIRS := $(SUB_DIRS) char
L_OBJS :=
@@ -18,7 +18,7 @@ MOD_LIST_NAME := SGI_MODULES
# Character and Audio devices for SGI machines.
#
-SUB_DIRS += char audio
-L_OBJS += char/sgichar.o audio/sgiaudio.o
+SUB_DIRS += char
+L_OBJS += char/sgichar.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/sgi/audio/Makefile b/drivers/sgi/audio/Makefile
deleted file mode 100644
index 2b0a4a3d4..000000000
--- a/drivers/sgi/audio/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-#
-# sgi audio drivers
-#
-
-O_TARGET := sgiaudio.o
-O_OBJS :=
-M_OBJS :=
-M :=
-MM :=
-
-
-
-
-
-ifeq ($(CONFIG_SGI_HAL2),y)
-M=y
-OX_OBJS += hal2.o
-else
- ifeq ($(CONFIG_SGI_HAL2),m)
- MM=y
- MX_OBJS += hal2.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
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
diff --git a/drivers/sgi/audio/hal2.h b/drivers/sgi/audio/hal2.h
deleted file mode 100644
index 64a72a5c2..000000000
--- a/drivers/sgi/audio/hal2.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * drivers/sgi/audio/hal2.h
- *
- * Copyright (C) 1998 Ulf Carlsson (ulfc@bun.falkenberg.se)
- *
- */
-
-#define H2_HAL2_BASE (HPC3_CHIP0_PBASE + 0x58000)
-#define H2_CTRL_PIO (H2_HAL2_BASE + 0 * 0x200)
-#define H2_AES_PIO (H2_HAL2_BASE + 1 * 0x200)
-#define H2_VOLUME_PIO (H2_HAL2_BASE + 2 * 0x200)
-#define H2_SYNTH_PIO (H2_HAL2_BASE + 3 * 0x200)
-
-typedef volatile unsigned int hal_reg;
-
-struct hal2_ctrl_regs {
- hal_reg _unused0[4];
- hal_reg isr; /* 0x10 Status Register */
- hal_reg _unused1[3];
- hal_reg rev; /* 0x20 Revision Register */
- hal_reg _unused2[3];
- hal_reg iar; /* 0x30 Indirect Address Register */
- hal_reg _unused3[3];
- hal_reg idr0; /* 0x40 Indirect Data Register 0 */
- hal_reg _unused4[3];
- hal_reg idr1; /* 0x50 Indirect Data Register 1 */
- hal_reg _unused5[3];
- hal_reg idr2; /* 0x60 Indirect Data Register 2 */
- hal_reg _unused6[3];
- hal_reg idr3; /* 0x70 Indirect Data Register 3 */
-} volatile *h2_ctrl = (struct hal2_ctrl_regs *) KSEG1ADDR(H2_CTRL_PIO);
-
-struct hal2_vol_regs {
- hal_reg right; /* 0x00 Right volume */
- hal_reg left; /* 0x04 Left volume */
-} volatile *h2_vol = (struct hal2_vol_regs *) KSEG1ADDR(H2_VOLUME_PIO);
-
-/* AES and synth regs should end up here if we ever support them */
-
-/* Indirect status register */
-
-#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */
-#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */
-#define H2_ISR_CODEC_MODE 0x04 /* codec mode 0=indigo 1=quad */
-#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */
-#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */
-
- /* Revision register */
-
-#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */
-#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */
-#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */
-#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */
-
-/* Indirect address register */
-
-/*
- * Address of indirect internal register to be accessed. A write to this
- * register initiates read or write access to the indirect registers in the
- * HAL2. Note that there af four indirect data registers for write access to
- * registers larger than 16 byte.
- */
-
-#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */
- /* block the register resides in */
- /* 1=DMA Port */
- /* 9=Global DMA Control */
- /* 2=Bresenham */
- /* 3=Unix Timer */
-#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */
- /* blockin which the indirect */
- /* register resides */
- /* If IAR_TYPE_M=DMA Port: */
- /* 1=Synth In */
- /* 2=AES In */
- /* 3=AES Out */
- /* 4=DAC Out */
- /* 5=ADC Out */
- /* 6=Synth Control */
- /* If IAR_TYPE_M=Global DMA Control: */
- /* 1=Control */
- /* If IAR_TYPE_M=Bresenham: */
- /* 1=Bresenham Clock Gen 1 */
- /* 2=Bresenham Clock Gen 2 */
- /* 3=Bresenham Clock Gen 3 */
- /* If IAR_TYPE_M=Unix Timer: */
- /* 1=Unix Timer */
-#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */
-#define H2_IAR_PARAM 0x000C /* Parameter Select */
-#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */
- /* 00:word0 */
- /* 01:word1 */
- /* 10:word2 */
- /* 11:word3 */
-/*
- * HAL2 internal addressing
- *
- * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
- * Indirect Data registers. Write the address to the Indirect Address register
- * to transfer the data.
- *
- * We define the H2IR_* to the read address and H2IW_* to the write address and
- * H2I_* to be fields in whatever register is referred to.
- *
- * When we write to indirect registers which are larger than one word (16 bit)
- * we have to fill more than one indirect register before writing. When we read
- * back however we have to read several times, each time with different Read
- * Back Indexes (there are defs for doing this easily).
- */
-
-/*
- * Relay Control
- */
-#define H2IW_RELAY_C 0x9100 /* state of RELAY pin signal */
-#define H2IR_RELAY_C 0x9180 /* state of RELAY pin signal */
-#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */
-
-#define H2IW_DMA_PORT_EN 0x09104 /* dma port enable */
-#define H2IR_DMA_PORT_EN 0x9184 /* dma port enable */
-#define H2I_DMA_PORT_EN_SY_IN 0x01 /* synth_in dma port */
-#define H2I_DMA_PORT_EN_AESRX 0x02 /* aes receiver dma port */
-#define H2I_DMA_PORT_EN_AESTX 0x04 /* aes transmitter dma port */
-#define H2I_DMA_PORT_EN_CODECTX 0x08 /* codec transmit dma port */
-#define H2I_DMA_PORT_EN_CODECR 0x10 /* codec receive dma port */
- /* 0=disable 1=enable */
-
-#define H2IW_DMA_END 0x9108 /* global dma endian select */
-#define H2IR_DMA_END 0x9188 /* global dma endian select */
-#define H2I_DMA_END_SY_IN 0x01 /* synth_in dma port */
-#define H2I_DMA_END_AESRX 0x02 /* aes receiver dma port */
-#define H2I_DMA_END_AESTX 0x04 /* aes transmitter dma port */
-#define H2I_DMA_END_CODECTX 0x08 /* codec transmit dma port */
-#define H2I_DMA_END_CODECR 0x10 /* codec receive dma port */
- /* 0=big endian 1=little endian */
-
-#define H2IW_DMA_DRV 0x910C /* global dma bus drive enable */
-#define H2IR_DMA_DRV 0x918C /* global dma bus drive enable */
-
-#define H2IW_SYNTH_C 0x1104 /* synth dma control write */
-#define H2IR_SYNTH_C 0x1184 /* synth dma control read */
-
-#define H2IW_AESRX_C 0x1204 /* aes rx dma control write */
-#define H2IR_AESRX_C 0x1284 /* aes rx dma control read */
-#define H2I_AESRX_C_TS_EN 0x20 /* timestamp enable 0=no 1=yes */
-#define H2I_AESRX_C_TS_FMT 0x40 /* timestamp format */
-#define H2I_AESRX_C_NAUDIO 0x80 /* pbus dma data format */
- /* 0=sign_ext 1=pass_non_audio */
-
-#define H2IW_AESTX_C 0x1304 /* aes tx dma control write */
-#define H2IR_AESTX_C 0x1384 /* aes tx dma control read */
-#define H2I_AESTX_C_CLKID_M 0x18 /* bits 4:3, clockid */
- /* 1=Bresenham Clock Gen 1 */
- /* 2=Bresenham Clock Gen 2 */
- /* 3=Bresenham Clock Gen 3 */
-#define H2I_AESTX_C_DTYPE 0x300 /* bits 9:8, datatype */
- /* 1=mono 2=stereo 3=quad */
-
-/* DAC */
-
-#define H2IW_DAC_C1 0x1404 /* dac tx dma control 1 write */
-#define H2IR_DAC_C1 0x1484 /* dac tx dma control 1 read */
-#define H2I_DAC_C1_CLKID 0x18 /* bits 4:3, clockid */
- /* 1=Bresenham Clock Gen 1 */
- /* 2=Bresenham Clock Gen 2 */
- /* 3=Bresenham Clock Gen 3 */
-#define H2I_DAC_C1_DTYPE 0x300 /* bits 9:8 datatype */
- /* 1=mono 2=stereo 3=quad */
-
-#define H2IW_DAC_C2 0x1408 /* dac control 2 write word 0 */
-#define H2IR_DAC_C2_0 0x1488 /* dac control 2 read word 0 */
-#define H2IR_DAC_C2_1 0x1489 /* dac control 2 read word 1 */
- /* XXX: The spec says 0x1488 */
-#define H2I_DAC_C2_0_R_GAIN 0x0f /* right a/d input gain bit 0-3 */
-#define H2I_DAC_C2_0_L_GAIN 0xf0 /* left a/d input gain bit 0-3 */
-#define H2I_DAC_C2_0_R_SEL 0x100 /* right a/d input select */
-#define H2I_DAC_C2_0_L_SEL 0x200 /* left a/d input select */
-#define H2I_DAC_C2_0_MUTE 0x400 /* 1=mute */
-#define H2I_DAC_C2_1_DO1 0x01 /* digital output port bit 1 */
-#define H2I_DAC_C2_1_DO2 0x02 /* digital output port bit 0 */
-#define H2I_DAC_C2_1_R_ATTEN 0x7c /* bits 6:2 right a/d output */
- /* attenuation, bit 0-4 (4=msb) */
-#define H2I_DAC_C2_1_L_ATTEN 0xf80 /* bits 11:7 left a/d output */
- /* attenuation, bit 0-4 (4=msb) */
-/* ADC */
-
-#define H2IW_ADC_C1 0x1504 /* adc tx dma control 1 write */
-#define H2IR_ADC_C1 0x1584 /* adc tx dma control 1 read */
-#define H2I_ADC_C1_CLKID 0x18 /* bits 4:3, clockid */
- /* 1=Bresenham Clock Gen 1 */
- /* 2=Bresenham Clock Gen 2 */
- /* 3=Bresenham Clock Gen 3 */
-#define H2I_ADC_C1_DTYPE 0x300 /* bits 9:8, datatype */
- /* 1=mono 2=stereo 3=quad */
-
-#define H2IW_ADC_C2 0x1508 /* adc control 2 write word 0-1 */
- /* both words have to be written at */
- /* the same time, fill idr[0-1] */
-#define H2IR_ADC_C2_0 0x1588 /* adc control 2 read word 0 */
-#define H2IR_ADC_C2_1 0x1589 /* adc control 2 read word 1 */
- /* XXX: The spec says 0x1588 */
-#define H2I_ADC_C2_0_R_GAIN 0x0f /* right a/d input gain bit 0-3 */
-#define H2I_ADC_C2_0_L_GAIN 0xf0 /* left a/d input gain bit 0-3 */
-#define H2I_ADC_C2_0_R_SEL 0x100 /* right a/d input select */
-#define H2I_ADC_C2_0_L_SEL 0x200 /* left a/d input select */
-#define H2I_ADC_C2_0_MUTE 0x400 /* 1=mute */
-#define H2I_ADC_C2_1_DO1 0x01 /* digital output port bit 1 */
-#define H2I_ADC_C2_1_DO2 0x02 /* digital output port bit 0 */
-#define H2I_ADC_C2_1_R_ATTEN 0x7c /* bits 6:2, right a/d output */
- /* attenuation, bit 0-4 (4=msb) */
-#define H2I_ADC_C2_1_L_ATTEN 0xf80 /* bits 11:7, left a/d output */
- /* attenuation, bit 0-4 (4=msb) */
-
-#define H2IW_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl write */
-#define H2IR_SYNTH_MAP_C 0x1184 /* synth dma handshake ctrl read */
-
-#define H2IW_BRES1_C1 0x2104 /* clock gen 1 ctrl 1 write */
-#define H2IR_BRES1_C1 0x2184 /* clock gen 1 ctrl 1 read */
-#define H2I_BRES1_C1_FSRSEL 0x03 /* master clock source */
- /* 0=48.0 1=44.1 2=aes_rx */
-
-#define H2IW_BRES1_C2 0x2108 /* clock gen 1 ctrl 2 write word 0-1 */
-#define H2IR_BRES1_C2_0 0x2188 /* clock gen 1 ctrl 2 read word 0 */
-#define H2IR_BRES1_C2_1 0x2189 /* clock gen 1 ctrl 2 read word 1 */
- /* XXX: The spec says 0x2188 */
-#define H2I_BRES1_C2_0_INC 0xffff /* increment value, inc <= mod */
-#define H2I_BRES1_C2_1_INC 0xffff /* modcontrol value, */
- /* modctrl=0x00ffff & (modinc-1) */
-
-#define H2IW_BRES2_C1 0x2204 /* clock gen 2 ctrl 1 write */
-#define H2IR_BRES2_C1 0x2284 /* clock gen 2 ctrl 1 read */
-#define H2I_BRES2_C1_FSRSEL 0x03 /* master clock source */
- /* 0=48.0 1=44.1 2=aes_rx */
-
-#define H2IW_BRES2_C2 0x2208 /* clock gen 2 ctrl 2 write word 0-1 */
-#define H2IR_BRES2_C2_0 0x2288 /* clock gen 2 ctrl 2 read word 0 */
-#define H2IR_BRES2_C2_1 0x2289 /* clock gen 2 ctrl 2 read word 1 */
-#define H2I_BRES2_C2_0_INC 0xffff /* increment value, inc <= mod */
-#define H2I_BRES2_C2_1_INC 0xffff /* modcontrol value, */
- /* modctrl=0x00ffff & (modinc-1) */
-
-#define H2IW_BRES3_C1 0x2304 /* clock gen 3 ctrl 1 write */
-#define H2IR_BRES3_C1 0x2384 /* clock gen 3 ctrl 1 read */
-#define H2I_BRES3_C1_FSRSEL 0x03 /* master clock source */
- /* 0=48.0 1=44.1 2=aes_rx */
-
-#define H2IW_BRES3_C2 0x2308 /* clock gen 3 ctrl 2 write word 0-1 */
-#define H2IR_BRES3_C2_0 0x2388 /* clock gen 3 ctrl 2 read word 0 */
-#define H2IR_BRES3_C2_1 0x2389 /* clock gen 3 ctrl 2 read word 1 */
-#define H2I_BRES3_C2_0_INC 0xffff /* increment value, inc <= mod */
-#define H2I_BRES3_C2_1_INC 0xffff /* modcontrol value, */
- /* modctrl=0x00ffff & (modinc-1) */
-
-#define H2IW_UTIME 0x3104 /* unix timer write (preload time) */
-#define H2IR_UTIME 0x3184 /* unix timer read */
-#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */
-#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */
-#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */
-#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */
-#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index b13122e4e..c7de93a50 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -16,6 +16,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
+ if [ "$CONFIG_SGI" = "y" ]; then
+ dep_tristate 'SGI Indy HAL2' CONFIG_SOUND_HAL2 $CONFIG_SOUND
+ fi
fi
dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index c4fb47dce..b76e03ce3 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
#jnx
obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o
+obj-$(CONFIG_SOUND_HAL2) += hal2.o
obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
# Declare multi-part drivers.
diff --git a/drivers/sound/hal2.c b/drivers/sound/hal2.c
new file mode 100644
index 000000000..6a70267cc
--- /dev/null
+++ b/drivers/sound/hal2.c
@@ -0,0 +1,1529 @@
+/* $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/poll.h>
+#include <linux/soundcard.h>
+#include <linux/sound.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
+
+static const unsigned sample_size[] = { 2, 4 };
+static const unsigned sample_shift[] = { 1, 2 };
+
+struct hal2_ring_buf {
+ struct hpc_dma_desc desc;
+
+ struct hal2_ring_buf *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_state {
+ /* soundcore stuff */
+ int dev_audio;
+ int dev_mixer;
+ int dev_dac;
+
+ int irq;
+
+ unsigned int dacrate, adcrate;
+
+ spinlock_t lock;
+ struct semaphore open_sem;
+ mode_t open_mode;
+ struct wait_queue *open_wait;
+
+ struct dmabuf {
+ void *rawbuf;
+ unsigned int buforder;
+ struct hal2_ring_buf *ringbuf;
+
+ struct hpc3_pbus_dmacregs *pbus;
+ int pbusnr;
+
+ unsigned int numfrag;
+ unsigned int fragshift;
+ int swptr;
+ int hwptr;
+
+ unsigned int total_bytes;
+
+ int count;
+ unsigned int error; /* over/underrun */
+ struct wait_queue *wait;
+
+
+ /* Internal flags */
+ unsigned little_end:1;
+ unsigned stereo:1;
+ unsigned receive:1;
+ unsigned pbus_setup:1;
+ unsigned pbus_en:1;
+ unsigned port_en:1;
+
+ /* redundant, but makes calculations easier */
+ unsigned fragsize;
+ unsigned dmasize;
+ unsigned fragsamples;
+
+ /* OSS stuff */
+ unsigned mapped:1;
+ unsigned ready:1;
+ unsigned endcleared:1;
+ unsigned ossfragshift;
+ int ossmaxfrags;
+ unsigned subdivision;
+ } dma_dac, dma_adc;
+};
+
+struct hal2_state *dev;
+
+/* ------------------------------------------------------------------------ */
+
+extern inline unsigned ld2(unsigned int x)
+{
+ unsigned r = 0;
+
+ if (x >= 0x10000) {
+ x >>= 16;
+ r += 16;
+ }
+ if (x >= 0x100) {
+ x >>= 8;
+ r += 8;
+ }
+ if (x >= 0x10) {
+ x >>= 4;
+ r += 4;
+ }
+ if (x >= 4) {
+ x >>= 2;
+ r += 2;
+ }
+ if (x >= 2)
+ r++;
+ return r;
+}
+
+/* ------------------------------------------------------------------ */
+
+#define INDIRECT_WAIT(regs) while(regs->isr & H2_ISR_TSTATUS);
+
+#if 0
+#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); \
+}
+#endif
+
+#define READ_ADDR(addr) (addr | (1<<7))
+#define WRITE_ADDR(addr) (addr)
+
+static unsigned short ireg_read16(unsigned short address)
+{
+
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ return h2_ctrl->idr0;
+}
+
+static unsigned long ireg_read32(unsigned short address)
+{
+ unsigned long ret;
+
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ ret = h2_ctrl->idr0;
+ h2_ctrl->iar = READ_ADDR(address | 0x1);
+ INDIRECT_WAIT(h2_ctrl);
+ ret |= h2_ctrl->idr0 << 16;
+ return ret;
+}
+
+static void ireg_write16(unsigned short address, unsigned short val)
+{
+ h2_ctrl->idr0 = val;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl)
+}
+
+static void ireg_write32(unsigned short address, unsigned long val)
+{
+ h2_ctrl->idr0 = val & 0xffff;
+ h2_ctrl->idr1 = val >> 16;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl)
+}
+
+static void ireg_write64(unsigned short address, unsigned long long val)
+{
+ h2_ctrl->idr0 = val & 0xffff;
+ h2_ctrl->idr1 = (val >> 16) & 0xffff;
+ h2_ctrl->idr2 = (val >> 32) & 0xffff;
+ h2_ctrl->idr3 = (val >> 48);
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl)
+}
+
+static void ireg_setbit16(unsigned short address, unsigned short bit)
+{
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ h2_ctrl->idr0 = h2_ctrl->idr0 | bit;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+static void ireg_setbit32(unsigned short address, unsigned long bit)
+{
+ unsigned long tmp;
+
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ tmp = h2_ctrl->idr0 | (h2_ctrl->idr1 << 16) | bit;
+ h2_ctrl->idr0 = tmp & 0xffff;
+ h2_ctrl->idr1 = (tmp >> 16) & 0xffff;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+static void ireg_clearbit16(unsigned long address, unsigned short bit)
+{
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ h2_ctrl->idr0 = h2_ctrl->idr0 & ~bit;
+ h2_ctrl->iar = address;
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+static void ireg_clearbit32(unsigned short address, unsigned long bit)
+{
+ unsigned long tmp;
+
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ tmp = (h2_ctrl->idr0 | (h2_ctrl->idr1 << 16)) & ~bit;
+ h2_ctrl->idr0 = tmp & 0xffff;
+ h2_ctrl->idr1 = (tmp >> 16) & 0xffff;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+static void ireg_setmask16(unsigned short address, int shift,
+ unsigned short mask, unsigned short bits)
+{
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ h2_ctrl->idr0 = (h2_ctrl->idr0 & ~mask) | (bits << shift);
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+static void ireg_setmask32(unsigned long address, int shift,
+ unsigned long mask, unsigned long bits)
+{
+ unsigned long tmp;
+
+ h2_ctrl->iar = READ_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+ tmp = ((h2_ctrl->idr1 | h2_ctrl->idr0) & ~mask) | (bits << shift);
+ h2_ctrl->idr0 = tmp & 0xffff;
+ h2_ctrl->idr1 = tmp >> 16;
+ h2_ctrl->iar = WRITE_ADDR(address);
+ INDIRECT_WAIT(h2_ctrl);
+}
+
+/* -----------------------------------------------------------------------*/
+
+/* enable/disable a specific PBUS dma channel */
+static __inline__ void hpcpbus_enable(struct hpc3_pbus_dmacregs *pbus,
+ struct hpc_dma_desc *desc)
+{
+ pbus->pbdma_dptr = PHYSADDR(desc);
+ pbus->pbdma_ctrl |= HPC3_PDMACTRL_ACT;
+}
+
+static __inline__ void hpcpbus_disable(struct hpc3_pbus_dmacregs *pbus)
+{
+ pbus->pbdma_ctrl &= ~HPC3_PDMACTRL_ACT;
+}
+
+static __inline__ int hpcpbus_int(struct hpc3_pbus_dmacregs *pbus)
+{
+ /* When we read pbdma_ctrl, bit 0 indicates interrupt signal.
+ * The interrupt signal is also cleared after read
+ */
+
+ return (pbus->pbdma_ctrl & 0x01);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* 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 * (inc / mod)
+ * freq * mod = master * inc
+ * mod = (master * inc) / freq
+ *
+ * where (inc / mod) is a positive fraction in range [0,1]. Inc should always be
+ * set to 4 for codecs
+ *
+ */
+
+#define __BUILD_SET_BRESN_CLOCK(clock) \
+static __inline__ void hal2_set_bres##clock(unsigned short master, \
+ unsigned long mod) \
+{ \
+ unsigned long incmod = (4 << 16) | mod; \
+ ireg_write16(H2I_BRES##clock##_C1 , master); \
+ ireg_write32(H2I_BRES##clock##_C2 , incmod); \
+}
+
+__BUILD_SET_BRESN_CLOCK(1)
+__BUILD_SET_BRESN_CLOCK(2)
+__BUILD_SET_BRESN_CLOCK(3)
+
+static int hal2_set_adc_rate(struct hal2_state *s, unsigned int rate)
+{
+ /* XXX how do i set this one? */
+
+ /* Try both 44.1k master and 48.0k master .. */
+
+ if ((48000 << 2) % rate == 0)
+ hal2_set_bres1(0, (48000 << 2) % rate);
+ else if ((44100 << 2) % rate == 0)
+ hal2_set_bres1(1, (44100 << 2) % rate);
+ else
+ /* this was no valid rate */
+ return -EINVAL;
+
+ return 0;
+}
+
+static int hal2_set_dac_rate(struct hal2_state *s, unsigned int rate)
+{
+ /* Try both 44.1k master and 48.0k master .. */
+
+ if ((48000 << 2) % rate == 0) {
+ hal2_set_bres1(0, (48000 << 2) % rate);
+ s->dacrate = rate;
+ } else if ((44100 << 2) % rate == 0) {
+ hal2_set_bres1(1, (44100 << 2) % rate);
+ s->dacrate = rate;
+ } else
+ /* this was no valid rate */
+ return -EINVAL;
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void hal2_stop(struct dmabuf *db)
+{
+ if (db->pbus_en) {
+ hpcpbus_disable(db->pbus);
+ db->pbus_en = 0;
+ }
+#ifdef DEBUG
+ else
+ printk("Trying to stop already stopped DMA channel\n");
+#endif
+}
+
+static void hal2_stop_adc(struct hal2_state *s)
+{
+ struct dmabuf *db = &s->dma_adc;
+
+ hal2_stop(db);
+}
+
+static void hal2_stop_dac(struct hal2_state *s)
+{
+ struct dmabuf *db = &s->dma_dac;
+
+ hal2_stop(db);
+}
+
+
+static void hal2_start_adc(struct hal2_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!s->dma_adc.port_en && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) {
+ hpcpbus_enable(s->dma_adc.pbus, &s->dma_adc.ringbuf->desc);
+ s->dma_adc.port_en = 1;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void hal2_start_dac(struct hal2_state *s)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+ if (!s->dma_dac.port_en && (s->dma_dac.mapped || s->dma_dac.count > 0)
+ && s->dma_dac.ready) {
+ hpcpbus_enable(s->dma_dac.pbus, &s->dma_dac.ringbuf->desc);
+ s->dma_dac.port_en = 1;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+static void hal2_dealloc_dmabuf(struct dmabuf *db)
+{
+ unsigned long map, mapend;
+
+ if (db->rawbuf) {
+ /* undo marking the pages as reserved */
+ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) -1);
+ for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+ clear_bit(PG_reserved, &mem_map[map].flags);
+ free_pages((unsigned long)db->rawbuf, db->buforder);
+ }
+ db->rawbuf = NULL;
+ db->mapped = db->ready = 0;
+}
+
+static int hal2_setup_ring(struct dmabuf *db)
+{
+ int order;
+ unsigned long buffer;
+ unsigned long map, mapend;
+ struct hal2_ring_buf *rbuf;
+ int i = 0;
+
+ /* FIXME: Clear up the memory leaks here */
+
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+ buffer = __get_free_pages(GFP_KERNEL, db->buforder);
+ if (buffer)
+ break;
+ }
+
+ if (!buffer)
+ return -ENOMEM;
+
+ db->buforder = order;
+ db->rawbuf = (void *) buffer;
+
+ /* we have to mark the pages as reserver, otherwise remap_page_range
+ * doesn't do what we want for some */
+
+ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+ for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+ set_bit(PG_reserved, &mem_map[map].flags);
+
+ db->ringbuf = kmalloc(sizeof (struct hal2_ring_buf), GFP_KERNEL);
+ if (!db->ringbuf)
+ return -ENOMEM;
+
+ rbuf = db->ringbuf;
+ rbuf->desc.pbuf = PHYSADDR(buffer + i * PAGE_SIZE);
+ rbuf->buf = KSEG1ADDR(buffer + i * PAGE_SIZE);
+ i++;
+
+ while (i++ < (1 << db->buforder)) {
+ rbuf->next = kmalloc(sizeof (struct hal2_ring_buf), GFP_KERNEL);
+ if (!db->ringbuf)
+ 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 */
+
+ rbuf->desc.pnext = PHYSADDR(buffer + i * PAGE_SIZE);
+
+ rbuf = rbuf->next;
+ rbuf->buf = KSEG1ADDR(buffer + i * PAGE_SIZE);
+ rbuf->desc.pbuf = PHYSADDR(buffer + i * PAGE_SIZE);
+ }
+
+ rbuf->next = db->ringbuf;
+ rbuf->desc.pnext = db->ringbuf->desc.pbuf; /* make it a ring! */
+
+ return 0;
+}
+
+static void hal2_reset_adc_ring(struct hal2_state *s)
+
+{
+ struct hal2_ring_buf *first, *rbuf;
+
+ first = s->dma_adc.ringbuf;
+
+ for (rbuf = first; rbuf->next != first; rbuf = rbuf->next)
+ rbuf->desc.cntinfo = HPCDMA_XIE | PAGE_SIZE;
+
+ rbuf->desc.cntinfo = HPCDMA_XIE | PAGE_SIZE;
+}
+
+static void hal2_reset_dac_ring(struct hal2_state *s)
+
+{
+ struct hal2_ring_buf *first, *rbuf;
+
+ first = s->dma_dac.ringbuf;
+
+ for (rbuf = first; rbuf->next != first; rbuf = rbuf->next)
+ rbuf->desc.cntinfo = HPCDMA_XIE | PAGE_SIZE;
+
+ rbuf->desc.cntinfo = HPCDMA_XIE | PAGE_SIZE;
+}
+
+static int hal2_setup_pbus(struct hal2_state *s, struct dmabuf *db, int pbusnr)
+{
+ struct hpc3_pbus_dmacregs *pbus = &hpc3c0->pbdma0;
+ int sampsz, highwater, fifosize;
+ unsigned long ctrl;
+ unsigned long fifobeg, fifoend;
+
+ db->pbusnr = pbusnr;
+ db->pbus = &pbus[pbusnr];
+
+ sampsz = (db->stereo ? 4 : 2);
+
+ /* an audio fifo should be 4 samples long and doubleword aligned,
+ highwater should be half the fifo size */
+
+ fifosize = (sampsz * 4) >> 3; /* doublewords */
+ highwater = (sampsz * 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
+ */
+
+ fifobeg = (db->pbusnr == 1) ? 0 : (4 * 4) >> 3;
+
+ fifoend = fifobeg + fifosize;
+
+ ctrl = HPC3_PDMACTRL_RT | (db->receive ? HPC3_PDMACTRL_RCV : 0) |
+ (db->little_end ? HPC3_PDMACTRL_SEL : 0);
+
+ pbus->pbdma_ctrl = (highwater << 8) | (fifobeg << 16) |
+ (fifoend << 24) | ctrl;
+
+ /* Realtime, 16-bit, cycles to spend and more default settings for
+ * soundcards, taken directly from the spec. */
+ hpc3c0->pbus_dmacfgs[db->pbusnr][0] = 0x8248844;
+
+ return 0;
+}
+
+static int hal2_prog_dmabuf(struct hal2_state *s, struct dmabuf *db,
+ unsigned rate)
+{
+ unsigned bytespersec;
+ unsigned bufs;
+ int err;
+
+ db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
+ db->endcleared = 0;
+
+ if (!db->rawbuf) {
+ db->ready = db->mapped = 0;
+ err = hal2_setup_ring(db);
+ if (err)
+ return err;
+ }
+
+ bytespersec = rate << sample_shift[db->stereo];
+ bufs = PAGE_SIZE << db->buforder;
+ if (db->ossfragshift) {
+ if ((1000 << db->ossfragshift) < bytespersec)
+ db->fragshift = ld2(bytespersec/1000);
+ else
+ db->fragshift = db->ossfragshift;
+ } else {
+ db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
+ if (db->fragshift < 3)
+ db->fragshift = 3;
+ }
+ db->numfrag = bufs >> db->fragshift;
+ while (db->numfrag < 4 && db->fragshift > 3) {
+ db->fragshift--;
+ db->numfrag = bufs >> db->fragshift;
+ }
+ db->fragsize = 1 << db->fragshift;
+ if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+ db->numfrag = db->ossmaxfrags;
+ db->fragsamples = db->fragsize >> sample_shift[db->stereo];
+ db->dmasize = db->numfrag << db->fragshift;
+ memset(db->rawbuf, 0, db->dmasize);
+ return 0;
+}
+
+static __inline__ int hal2_prog_dmabuf_adc(struct hal2_state *s)
+{
+ int err;
+
+ hal2_stop_adc(s);
+
+ err = hal2_setup_pbus(s, &s->dma_adc, 1);
+ if (err)
+ return err;
+
+ err = hal2_prog_dmabuf(s, &s->dma_adc, s->adcrate);
+ if (err)
+ return err;
+
+ hal2_reset_adc_ring(s);
+
+ hal2_set_adc_rate(s, s->adcrate);
+
+ ireg_write16(H2I_ADC_C1,
+ (0 << H2I_ADC_C1_DMA_SHIFT) |
+ (1 << H2I_ADC_C1_CLKID_SHIFT) |
+ (s->dma_adc.stereo << H2I_ADC_C1_DATAT_SHIFT));
+ ireg_setbit16(H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+
+ ireg_setbit16(H2I_DMA_DRV, (1 << 0));
+
+ s->dma_adc.ready = 1;
+
+ return 0;
+}
+
+static __inline__ int hal2_prog_dmabuf_dac(struct hal2_state *s)
+{
+ int err;
+
+ hal2_stop_adc(s);
+
+ err = hal2_setup_pbus(s, &s->dma_dac, 2);
+ if (err)
+ return err;
+
+ err = hal2_prog_dmabuf(s, &s->dma_dac, s->dacrate);
+ if (err)
+ return err;
+
+ hal2_reset_dac_ring(s);
+
+ hal2_set_dac_rate(s, s->dacrate);
+
+ ireg_write32(H2I_DAC_C1,
+ (1 << H2I_DAC_C1_DMA_SHIFT) |
+ (2 << H2I_DAC_C1_CLKID_SHIFT) |
+ (s->dma_dac.stereo << H2I_ADC_C1_DATAT_SHIFT));
+
+ ireg_setbit16(H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+
+ ireg_setbit16(H2I_DMA_DRV, (1 << 1));
+
+ s->dma_dac.ready = 1;
+
+ return 0;
+}
+
+static __inline__ unsigned int hal2_get_hwptr(struct hal2_state *s,
+ struct dmabuf *db)
+{
+ return db->pbus->pbdma_bptr;
+}
+
+extern __inline__ void clear_advance(void *buf, unsigned bsize, unsigned bptr,
+ unsigned len, unsigned char c)
+{
+ if (bptr + len > bsize) {
+ unsigned x = bsize - bptr;
+ memset(((char *)buf) + bptr, c, x);
+ bptr = 0;
+ len -= x;
+ }
+ memset(((char *)buf) + bptr, c, len);
+}
+
+static void hal2_update_ptr(struct hal2_state *s)
+{
+ int diff;
+
+ /* update ADC pointer */
+ if (s->dma_adc.port_en) {
+ diff = hal2_get_hwptr(s, &s->dma_adc);
+ s->dma_adc.total_bytes += diff;
+ s->dma_adc.count += diff;
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= s->dma_adc.fragsize)
+ wake_up(&s->dma_adc.wait);
+ } else {
+ if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+ hal2_stop_adc(s);
+ s->dma_adc.error++;
+ }
+ if (s->dma_adc.count > 0)
+ wake_up(&s->dma_adc.wait);
+ }
+ }
+
+ /* update DAC1 pointer */
+ if (s->dma_dac.port_en) {
+ diff = hal2_get_hwptr(s, &s->dma_dac);
+ s->dma_dac.total_bytes += diff;
+ if (s->dma_dac.mapped) {
+ s->dma_dac.count += diff;
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ wake_up(&s->dma_dac.wait);
+ } else {
+ s->dma_dac.count -= diff;
+ if (s->dma_dac.count <= 0) {
+ hal2_stop_dac(s);
+ s->dma_dac.error++;
+ } else if (s->dma_dac.count <=
+ (signed)s->dma_dac.fragsize &&
+ !s->dma_dac.endcleared) {
+ clear_advance(s->dma_dac.rawbuf,
+ s->dma_dac.dmasize,
+ s->dma_dac.swptr,
+ s->dma_dac.fragsize, 0);
+ s->dma_dac.endcleared = 1;
+ }
+ if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+ wake_up(&s->dma_dac.wait);
+ }
+ }
+}
+
+void hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct hal2_state *s = (struct hal2_state *) dev_id;
+
+ spin_lock(&s->lock);
+
+ if ((s->dma_adc.pbus_en && hpcpbus_int(s->dma_adc.pbus))||
+ (s->dma_dac.pbus_en && hpcpbus_int(s->dma_dac.pbus)))
+ hal2_update_ptr(s);
+
+ spin_unlock(&s->lock);
+}
+
+
+static __inline__ void hal2_clear_advance(void *buf, unsigned long bsize,
+ unsigned long bptr, unsigned int len,
+ unsigned char c)
+{
+ if (bptr + len > bsize) {
+ unsigned long x = bsize - bptr;
+ memset(((char *)buf) + bptr, c, x);
+ bptr = 0;
+ len -= x;
+ }
+ memset(((char *)buf) + bptr, c, len);
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static int hal2_drain_dac(struct hal2_state *s, int nonblock)
+{
+ struct wait_queue wait = { current, NULL };
+ unsigned long flags;
+ int count, tmo;
+
+ if (s->dma_dac.mapped)
+ return 0;
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&s->dma_dac.wait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (count * HZ) / s->dacrate;
+ tmo >>= sample_shift[(s->dma_dac.stereo)?0:1];
+
+ if (!schedule_timeout(tmo ? : 1) && tmo)
+ printk(KERN_DEBUG ": dma timed out??\n");
+ }
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static ssize_t hal2_read(struct file *file, char *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ if (!s)
+ return -ENXIO;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_adc.mapped)
+ return -ENXIO;
+ if (!s->dma_adc.ready && (ret = hal2_prog_dmabuf_adc(s)))
+ return ret;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ swptr = s->dma_adc.swptr;
+ cnt = s->dma_adc.dmasize-swptr;
+ if (s->dma_adc.count < cnt)
+ cnt = s->dma_adc.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ hal2_start_adc(s);
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EBUSY;
+ interruptible_sleep_on(&s->dma_adc.wait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_adc.dmasize;
+ spin_lock_irqsave(&s->lock, flags);
+ s->dma_adc.swptr = swptr;
+ s->dma_adc.count -= cnt;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ hal2_start_adc(s);
+ }
+ return ret;
+}
+
+static ssize_t hal2_write(struct file *file, const char *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+ ssize_t ret;
+ unsigned long flags;
+ unsigned swptr;
+ int cnt;
+
+ if (!s)
+ return -ENXIO;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (s->dma_dac.mapped)
+ return -ENXIO;
+ if (!s->dma_dac.ready && (ret = hal2_prog_dmabuf_dac(s)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ ret = 0;
+ while (count > 0) {
+ spin_lock_irqsave(&s->lock, flags);
+ if (s->dma_dac.count < 0) {
+ s->dma_dac.count = 0;
+ s->dma_dac.swptr = s->dma_dac.hwptr;
+ }
+ swptr = s->dma_dac.swptr;
+ cnt = s->dma_dac.dmasize-swptr;
+ if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+ cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ hal2_start_dac(s);
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EBUSY;
+ interruptible_sleep_on(&s->dma_dac.wait);
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+ continue;
+ }
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+ return ret ? ret : -EFAULT;
+ swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ spin_lock_irqsave(&s->lock, flags);
+ s->dma_dac.swptr = swptr;
+ s->dma_dac.count += cnt;
+ s->dma_dac.endcleared = 0;
+ spin_unlock_irqrestore(&s->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ hal2_start_dac(s);
+ }
+ return ret;
+}
+
+
+static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (!s)
+ return -EINVAL;
+ if (file->f_flags & FMODE_WRITE)
+ poll_wait(file, &s->dma_dac.wait, wait);
+ if (file->f_flags & FMODE_READ)
+ poll_wait(file, &s->dma_adc.wait, wait);
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ if (file->f_flags & FMODE_READ) {
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+ mask |= POLLIN | POLLRDNORM;
+ } else {
+ if (s->dma_adc.count > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ }
+ if (file->f_flags & FMODE_WRITE) {
+ if (s->dma_dac.mapped) {
+ if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ } else {
+ if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ return mask;
+}
+
+static int hal2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+ struct dmabuf *db;
+ int ret;
+ unsigned long size;
+
+ if (!s)
+ return -EINVAL;
+ if (vma->vm_flags & VM_WRITE) {
+ if ((ret = hal2_prog_dmabuf_dac(s)) != 0)
+ return ret;
+ db = &s->dma_dac;
+ } else if (vma->vm_flags & VM_READ) {
+ if ((ret = hal2_prog_dmabuf_adc(s)) != 0)
+ return ret;
+ db = &s->dma_adc;
+ } else
+ return -EINVAL;
+ if (vma->vm_offset != 0)
+ return -EINVAL;
+ size = vma->vm_end - vma->vm_start;
+ if (size > (PAGE_SIZE << db->buforder))
+ return -EINVAL;
+ if (remap_page_range(vma->vm_start, PHYSADDR(db->rawbuf), size, vma->vm_page_prot))
+ return -EAGAIN;
+ db->mapped = 1;
+ vma->vm_file = file;
+ file->f_count++;
+ return 0;
+}
+
+static int hal2_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ count_info cinfo;
+ int val, mapped, ret;
+
+ if (!s)
+ return -EINVAL;
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ /* XXX check what drain really should do */
+ return hal2_drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ /* XXX do we really support trigger? */
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+ DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(s);
+ synchronize_irq();
+ s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(s);
+ synchronize_irq();
+ s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ }
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val >= 0) {
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(s);
+ s->dma_adc.ready = 0;
+ hal2_set_adc_rate(s, val);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(s);
+ s->dma_dac.ready = 0;
+ hal2_set_dac_rate(s, val);
+ }
+ }
+ return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dacrate, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(s);
+ s->dma_adc.ready = 0;
+ spin_lock_irqsave(&s->lock, flags);
+ if (val) {
+ ireg_setmask16(H2I_ADC_C1,
+ H2I_ADC_C1_DATAT_SHIFT,
+ H2I_ADC_C1_DATAT_M, 2);
+ s->dma_adc.stereo = 1;
+ } else {
+ ireg_setmask16(H2I_ADC_C1,
+ H2I_ADC_C1_DATAT_SHIFT,
+ H2I_ADC_C1_DATAT_M, 1);
+ s->dma_adc.stereo = 0;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(s);
+ s->dma_dac.ready = 0;
+ spin_lock_irqsave(&s->lock, flags);
+ if (val) {
+ ireg_setmask16(H2I_DAC_C1,
+ H2I_DAC_C1_DATAT_SHIFT,
+ H2I_DAC_C1_DATAT_M, 2);
+ s->dma_dac.stereo = 1;
+ } else {
+ ireg_setmask16(H2I_DAC_C1,
+ H2I_DAC_C1_DATAT_SHIFT,
+ H2I_DAC_C1_DATAT_M, 1);
+ s->dma_dac.stereo = 0;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 0) {
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(s);
+ s->dma_adc.ready = 0;
+ spin_lock_irqsave(&s->lock, flags);
+ if (val >= 2) {
+ ireg_setmask16(H2I_ADC_C1,
+ H2I_ADC_C1_DATAT_SHIFT,
+ H2I_ADC_C1_DATAT_M, 2);
+ s->dma_dac.stereo = 1;
+ } else {
+ ireg_setmask16(H2I_ADC_C1,
+ H2I_ADC_C1_DATAT_SHIFT,
+ H2I_ADC_C1_DATAT_M, 1);
+ s->dma_adc.stereo = 0;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(s);
+ s->dma_dac.ready = 0;
+ spin_lock_irqsave(&s->lock, flags);
+ if (val >= 2) {
+ ireg_setmask16(H2I_DAC_C1,
+ H2I_DAC_C1_DATAT_SHIFT,
+ H2I_DAC_C1_DATAT_M, 2);
+ s->dma_dac.stereo = 1;
+ } else {
+ ireg_setmask16(H2I_DAC_C1,
+ H2I_DAC_C1_DATAT_SHIFT,
+ H2I_DAC_C1_DATAT_M, 1);
+ s->dma_dac.stereo = 0;
+ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+ }
+ return put_user(s->dma_dac.stereo ? 2 : 1, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_S16_BE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Maybe Little endian too */
+ return put_user(AFMT_S16_BE, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && s->dma_adc.port_en)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && s->dma_dac.port_en)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!s->dma_adc.ready && (ret = hal2_prog_dmabuf_adc(s)))
+ return ret;
+ hal2_start_adc(s);
+ } else
+ hal2_stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = hal2_prog_dmabuf_dac(s)))
+ return ret;
+ hal2_start_dac(s);
+ } else
+ hal2_stop_dac(s);
+ }
+ return 0;
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!s->dma_dac.port_en && (val = hal2_prog_dmabuf_dac(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ abinfo.fragsize = s->dma_dac.fragsize;
+ abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ abinfo.fragstotal = s->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ if (!(s->dma_adc.port_en) && (val = hal2_prog_dmabuf_adc(s)) != 0)
+ return val;
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ val = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ cinfo.bytes = s->dma_adc.total_bytes;
+ cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift;
+ cinfo.ptr = s->dma_adc.hwptr;
+ if (s->dma_adc.mapped)
+ s->dma_adc.count &= s->dma_adc.fragsize-1;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->lock, flags);
+ hal2_update_ptr(s);
+ cinfo.bytes = s->dma_dac.total_bytes;
+ cinfo.blocks = s->dma_dac.total_bytes >> s->dma_dac.fragshift;
+ cinfo.ptr = s->dma_dac.hwptr;
+ if (s->dma_dac.mapped)
+ s->dma_dac.count &= s->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&s->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = hal2_prog_dmabuf_dac(s)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = hal2_prog_dmabuf_adc(s)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ s->dma_adc.ossfragshift = val & 0xffff;
+ s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_adc.ossfragshift < 4)
+ s->dma_adc.ossfragshift = 4;
+ if (s->dma_adc.ossfragshift > 15)
+ s->dma_adc.ossfragshift = 15;
+ if (s->dma_adc.ossmaxfrags < 4)
+ s->dma_adc.ossmaxfrags = 4;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->dma_dac.ossfragshift = val & 0xffff;
+ s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_dac.ossfragshift < 4)
+ s->dma_dac.ossfragshift = 4;
+ if (s->dma_dac.ossfragshift > 15)
+ s->dma_dac.ossfragshift = 15;
+ if (s->dma_dac.ossmaxfrags < 4)
+ s->dma_dac.ossmaxfrags = 4;
+ }
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 1 && val != 2 && val != 4)
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ s->dma_adc.subdivision = val;
+ if (file->f_mode & FMODE_WRITE)
+ s->dma_dac.subdivision = val;
+ return 0;
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_RATE:
+ case SOUND_PCM_READ_CHANNELS:
+ case SOUND_PCM_READ_BITS:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+
+ }
+ return -EINVAL;
+}
+
+static int hal2_open(struct inode *inode, struct file *file)
+{
+ struct hal2_state *s = dev;
+
+ if (!s)
+ return -ENODEV;
+ file->private_data = s;
+ /* wait for device to become free */
+ down(&s->open_sem);
+ while (s->open_mode & file->f_mode) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem);
+ return -EBUSY;
+ }
+ up(&s->open_sem);
+ interruptible_sleep_on(&s->open_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem);
+ }
+ if (file->f_mode & FMODE_READ) {
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+ hal2_set_adc_rate(s, 8000);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+ hal2_set_dac_rate(s, 8000);
+ }
+ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ up(&s->open_sem);
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int hal2_release(struct inode *inode, struct file *file)
+{
+ struct hal2_state *s = (struct hal2_state *)file->private_data;
+
+ if (!s)
+ return -ENODEV;
+ if (file->f_mode & FMODE_WRITE)
+ hal2_drain_dac(s, file->f_flags & O_NONBLOCK);
+ down(&s->open_sem);
+ if (file->f_flags & FMODE_WRITE) {
+ hal2_stop_dac(s);
+ hal2_dealloc_dmabuf(&s->dma_dac);
+ }
+ if (file->f_flags & FMODE_READ) {
+ hal2_stop_adc(s);
+ hal2_dealloc_dmabuf(&s->dma_adc);
+ }
+ s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+ up(&s->open_sem);
+ wake_up(&s->open_wait);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static struct file_operations hal2_audio_fops = {
+ NULL, /* hal2_llseek */
+ hal2_read,
+ hal2_write,
+ NULL, /* hal2_readdir */
+ hal2_poll,
+ hal2_ioctl,
+ hal2_mmap,
+ hal2_open,
+ NULL, /* hal2_flush */
+ hal2_release,
+ NULL, /* hal2_fsync */
+ NULL, /* hal2_fasync */
+ NULL, /* hal2_check_media_change */
+ NULL, /* hal2_revalidate */
+ NULL, /* hal2_lock */
+};
+
+/* ----------------------------------------------------------------------- */
+
+static void hal2_reset(void)
+{
+ printk("resetting global isr:%04hx\n", h2_ctrl->isr);
+#if 0
+ /* try to leave the card in the bootup state so that the mixer stuff
+ * isn't gone */
+ h2_ctrl->isr = 0; /* reset the card */
+#endif
+ 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);
+}
+
+static int hal2_probe(void)
+{
+ unsigned short board, major, minor;
+
+ unsigned long 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: probing card\n");
+#endif
+
+ /* check that the indirect registers are working by writing some bogus
+ * stuff and then reading it back */
+
+ ireg_write16(H2I_DAC_C1, 0x4084); /* 16 bit register */
+ ireg_write32(H2I_BRES2_C2, 0x20C0084); /* 32 bit register */
+
+#ifdef DEBUG
+ printk("hal2: write done\n");
+#endif
+
+ if ((tmp = ireg_read16(H2I_DAC_C1)) != 0x4084) {
+ printk("hal2: Didn't pass register check #1 (%04lx)\n", tmp);
+ return -ENODEV;
+ }
+ if ((tmp = ireg_read32(H2I_BRES2_C2)) != 0x20C0084) {
+ printk("hal2: Didn't pass register check #2 (%08lx)\n", tmp);
+ return -ENODEV;
+ }
+
+#ifdef DEBUG
+ printk("hal2: read done\n");
+#endif
+ printk("hal2: card found\n");
+
+ return 0;
+}
+
+static int hal2_init(void)
+{
+ static int initialized = 0;
+
+ if (initialized) {
+ printk("hal2: already initialized?\n");
+ return 0;
+ }
+
+ if (!dev) {
+#ifdef DEBUG
+ printk("hal2: allocating hal2 device pointer\n");
+#endif
+ dev = kmalloc(sizeof(struct hal2_state), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ memset(dev, 0, sizeof(struct hal2_state));
+ }
+
+#ifdef DEBUG
+ printk("hal2: resetting chip\n");
+#endif
+ hal2_reset();
+
+ /* setup indigo codec mode */
+
+#ifdef DEBUG
+ printk("hal2: init done\n");
+#endif
+
+ initialized = 1;
+
+ return 0;
+}
+
+
+#ifdef MODULE
+__initfunc(int init_module(void))
+#else
+__initfunc(int init_hal2(void))
+#endif
+{
+ struct hal2_state *s;
+ int err;
+
+ err = hal2_probe();
+ if (err)
+ return err;
+
+ err = hal2_init();
+ if (err)
+ return err;
+
+ s = dev;
+
+ memset(s, 0, sizeof(struct hal2_state));
+ init_waitqueue(&s->dma_adc.wait);
+ init_waitqueue(&s->dma_dac.wait);
+ init_waitqueue(&s->open_wait);
+ s->open_sem = MUTEX;
+
+ /* Indigo CODEC mode (!QUAD) */
+ h2_ctrl->isr &= ~H2_ISR_QUAD_MODE;
+
+ s->irq = 12; /* wild guess! */
+ err = request_irq(s->irq, hal2_interrupt, SA_INTERRUPT, "hal2", s);
+ if (err) {
+ printk(KERN_ERR "hal2: irq %u in use\n", s->irq);
+ return err;
+ }
+ s->dev_audio = register_sound_dsp(&hal2_audio_fops);
+ if (s->dev_audio < 0)
+ printk(KERN_ERR "hal2: cannot register misc device\n");
+
+ hal2_set_adc_rate(s, 22050);
+ hal2_set_dac_rate(s, 22050);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+ struct hal2_state *s = dev;
+
+ synchronize_irq();
+ free_irq(s->irq, s);
+ unregister_sound_dsp(s->dev_audio);
+ kfree_s(s, sizeof(struct hal2_state));
+ printk(KERN_INFO "hal2: unloading\n");
+}
+
+#endif
diff --git a/drivers/sound/hal2.h b/drivers/sound/hal2.h
new file mode 100644
index 000000000..1749534ce
--- /dev/null
+++ b/drivers/sound/hal2.h
@@ -0,0 +1,259 @@
+/*
+ * drivers/sgi/audio/hal2.h
+ *
+ * Copyright (C) 1998 Ulf Carlsson (ulfc@bun.falkenberg.se)
+ *
+ */
+
+#define H2_HAL2_BASE (HPC3_CHIP0_PBASE + 0x58000)
+#define H2_CTRL_PIO (H2_HAL2_BASE + 0 * 0x200)
+#define H2_AES_PIO (H2_HAL2_BASE + 1 * 0x200)
+#define H2_VOLUME_PIO (H2_HAL2_BASE + 2 * 0x200)
+#define H2_SYNTH_PIO (H2_HAL2_BASE + 3 * 0x200)
+
+typedef volatile unsigned int hal_reg;
+
+struct hal2_ctrl_regs {
+ hal_reg _unused0[4];
+ hal_reg isr; /* 0x10 Status Register */
+ hal_reg _unused1[3];
+ hal_reg rev; /* 0x20 Revision Register */
+ hal_reg _unused2[3];
+ hal_reg iar; /* 0x30 Indirect Address Register */
+ hal_reg _unused3[3];
+ hal_reg idr0; /* 0x40 Indirect Data Register 0 */
+ hal_reg _unused4[3];
+ hal_reg idr1; /* 0x50 Indirect Data Register 1 */
+ hal_reg _unused5[3];
+ hal_reg idr2; /* 0x60 Indirect Data Register 2 */
+ hal_reg _unused6[3];
+ hal_reg idr3; /* 0x70 Indirect Data Register 3 */
+} volatile *h2_ctrl = (struct hal2_ctrl_regs *) KSEG1ADDR(H2_CTRL_PIO);
+
+struct hal2_vol_regs {
+ hal_reg right; /* 0x00 Right volume */
+ hal_reg left; /* 0x04 Left volume */
+} volatile *h2_vol = (struct hal2_vol_regs *) KSEG1ADDR(H2_VOLUME_PIO);
+
+/* AES and synth regs should end up here if we ever support them */
+
+/* Indirect status register */
+
+#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */
+#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */
+#define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */
+#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */
+#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */
+
+ /* Revision register */
+
+#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */
+#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */
+#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */
+#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */
+
+/* Indirect address register */
+
+/*
+ * Address of indirect internal register to be accessed. A write to this
+ * register initiates read or write access to the indirect registers in the
+ * HAL2. Note that there af four indirect data registers for write access to
+ * registers larger than 16 byte.
+ */
+
+#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */
+ /* block the register resides in */
+ /* 1=DMA Port */
+ /* 9=Global DMA Control */
+ /* 2=Bresenham */
+ /* 3=Unix Timer */
+#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */
+ /* blockin which the indirect */
+ /* register resides */
+ /* If IAR_TYPE_M=DMA Port: */
+ /* 1=Synth In */
+ /* 2=AES In */
+ /* 3=AES Out */
+ /* 4=DAC Out */
+ /* 5=ADC Out */
+ /* 6=Synth Control */
+ /* If IAR_TYPE_M=Global DMA Control: */
+ /* 1=Control */
+ /* If IAR_TYPE_M=Bresenham: */
+ /* 1=Bresenham Clock Gen 1 */
+ /* 2=Bresenham Clock Gen 2 */
+ /* 3=Bresenham Clock Gen 3 */
+ /* If IAR_TYPE_M=Unix Timer: */
+ /* 1=Unix Timer */
+#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */
+#define H2_IAR_PARAM 0x000C /* Parameter Select */
+#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */
+ /* 00:word0 */
+ /* 01:word1 */
+ /* 10:word2 */
+ /* 11:word3 */
+/*
+ * HAL2 internal addressing
+ *
+ * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
+ * Indirect Data registers. Write the address to the Indirect Address register
+ * to transfer the data.
+ *
+ * We define the H2IR_* to the read address and H2IW_* to the write address and
+ * H2I_* to be fields in whatever register is referred to.
+ *
+ * When we write to indirect registers which are larger than one word (16 bit)
+ * we have to fill more than one indirect register before writing. When we read
+ * back however we have to read several times, each time with different Read
+ * Back Indexes (there are defs for doing this easily).
+ */
+
+/*
+ * Relay Control
+ */
+#define H2I_RELAY_C 0x9100
+#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */
+
+/* DMA port enable */
+
+#define H2I_DMA_PORT_EN 0x9104
+#define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */
+#define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */
+#define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */
+#define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */
+#define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */
+
+#define H2I_DMA_END 0x9108 /* global dma endian select */
+#define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */
+#define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */
+#define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */
+#define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */
+#define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */
+ /* 0=b_end 1=l_end */
+
+#define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */
+
+#define H2I_SYNTH_C 0x1104 /* Synth DMA control */
+
+#define H2I_AESRX_C 0x1204 /* AES RX dma control */
+#define H2I_AESRX_C_TS_EN 0x20 /* timestamp enable */
+#define H2I_AESRX_C_TS_FMT 0x40 /* timestamp format */
+#define H2I_AESRX_C_NAUDIO 0x80 /* PBUS DMA data format */
+
+/* AESRX CTRL, 16 bit */
+
+#define H2I_AESTX_C 0x1304 /* AES TX DMA control */
+#define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
+#define H2I_AESTX_C_CLKID_M 0x18
+#define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
+#define H2I_AESTX_C_DATAT_M 0x300
+
+/* DAC CTRL1, 16 bit */
+
+#define H2I_DAC_C1 0x1404 /* DAC dma control */
+#define H2I_DAC_C1_DMA_SHIFT 0 /* DMA channel */
+#define H2I_DAC_C1_DMA_M 0x7
+#define H2I_DAC_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
+#define H2I_DAC_C1_CLKID_M 0x18
+#define H2I_DAC_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
+#define H2I_DAC_C1_DATAT_M 0x300
+
+/* DAC CTRL2, 32 bit */
+
+#define H2I_DAC_C2 0x1408
+#define H2I_DAC_C2_RGAIN_SHIFT 0 /* right a/d input gain */
+#define H2I_DAC_C2_R_GAIN_M 0xf
+#define H2I_DAC_C2_L_GAIN_SHIFT 4 /* left a/d input gain */
+#define H2I_DAC_C2_L_GAIN_M 0xf0
+#define H2I_DAC_C2_R_SEL 0x100 /* right input select */
+#define H2I_DAC_C2_L_SEL 0x200 /* left input select */
+#define H2I_DAC_C2_MUTE 0x400 /* mute */
+#define H2I_DAC_C2_DO1 0x10000 /* digital output port bit 0 */
+#define H2I_DAC_C2_DO2 0x20000 /* digital output port bit 1 */
+#define H2I_DAC_C2_R_ATT_SHIFT 18 /* right a/d output - */
+#define H2I_DAC_C2_R_ATT_M 0x7c0000 /* attenuation */
+#define H2I_DAC_C2_L_ATT_SHIFT 23 /* left a/d output - */
+#define H2I_DAC_C2_L_ATT_M 0x0000f80 /* attenuation */
+
+/* ADC CTRL1, 16 bit */
+
+#define H2I_ADC_C1 0x1504 /* DAC dma control */
+#define H2I_ADC_C1_DMA_SHIFT 0 /* DMA channel */
+#define H2I_ADC_C1_DMA_M 0x7
+#define H2I_ADC_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
+#define H2I_ADC_C1_CLKID_M 0x18
+#define H2I_ADC_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
+#define H2I_ADC_C1_DATAT_M 0x300
+
+/* ADC CTRL2, 32 bit */
+
+#define H2I_ADC_C2 0x1508
+#define H2I_ADC_C2_RGAIN_SHIFT 0 /* right a/d input gain */
+#define H2I_ADC_C2_R_GAIN_M 0xf
+#define H2I_ADC_C2_L_GAIN_SHIFT 4 /* left a/d input gain */
+#define H2I_ADC_C2_L_GAIN_M 0xf0
+#define H2I_ADC_C2_R_SEL 0x100 /* right input select */
+#define H2I_ADC_C2_L_SEL 0x200 /* left input select */
+#define H2I_ADC_C2_MUTE 0x400 /* mute */
+#define H2I_ADC_C2_DO1 0x10000 /* digital output port bit 0 */
+#define H2I_ADC_C2_DO2 0x20000 /* digital output port bit 1 */
+#define H2I_ADC_C2_R_ATT_SHIFT 18 /* right a/d output - */
+#define H2I_ADC_C2_R_ATT_M 0x7c0000 /* attenuation */
+#define H2I_ADC_C2_L_ATT_SHIFT 23 /* left a/d output - */
+#define H2I_ADC_C2_L_ATT_M 0x0000f80 /* attenuation */
+
+
+#define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */
+
+/* Clock generator 1 CTRL 1, 16 bit */
+
+#define H2I_BRES1_C1 0x2104
+#define H2I_BRES1_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */
+#define H2I_BRES1_C1_M 0x03
+
+/* Clock generator 1 CTRL 2, 32 bit */
+
+#define H2I_BRES1_C2 0x2108
+#define H2I_BRES1_C2_INC_SHIFT 0 /* increment value */
+#define H2I_BRES1_C2_INC_M 0xffff
+#define H2I_BRES1_C2_MOD_SHIFT 16 /* modcontrol value */
+#define H2I_BRES1_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */
+
+/* Clock generator 2 CTRL 1, 16 bit */
+
+#define H2I_BRES2_C1 0x2204
+#define H2I_BRES2_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */
+#define H2I_BRES2_C1_M 0x03
+
+/* Clock generator 2 CTRL 2, 32 bit */
+
+#define H2I_BRES2_C2 0x2208
+#define H2I_BRES2_C2_INC_SHIFT 0 /* increment value */
+#define H2I_BRES2_C2_INC_M 0xffff
+#define H2I_BRES2_C2_MOD_SHIFT 16 /* modcontrol value */
+#define H2I_BRES2_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */
+
+/* Clock generator 3 CTRL 1, 16 bit */
+
+#define H2I_BRES3_C1 0x2304
+#define H2I_BRES3_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */
+#define H2I_BRES3_C1_M 0x03
+
+/* Clock generator 3 CTRL 2, 32 bit */
+
+#define H2I_BRES3_C2 0x2308
+#define H2I_BRES3_C2_INC_SHIFT 0 /* increment value */
+#define H2I_BRES3_C2_INC_M 0xffff
+#define H2I_BRES3_C2_MOD_SHIFT 16 /* modcontrol value */
+#define H2I_BRES3_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */
+
+/* Unix timer, 64 bit */
+
+#if 0
+#define H2I_UTIME 0x3104
+#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */
+#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */
+#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */
+#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */
+#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */
+#endif