/*
* Driver for A2 audio system used in SGI machines
* Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org>
*
* Based on Ulf Carlsson's code.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Supported devices:
* /dev/dsp standard dsp device, (mostly) OSS compatible
* /dev/mixer standard mixer device, (mostly) OSS compatible
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
#include "hal2.h"
#if 0
#define DEBUG(args...) printk(args)
#else
#define DEBUG(args...)
#endif
#if 0
#define DEBUG_MIX(args...) printk(args)
#else
#define DEBUG_MIX(args...)
#endif
/*
* Before touching these look how it works. It is a bit unusual I know,
* but it helps to keep things simple. This driver is considered complete
* and I won't add any new features although hardware has many cool
* capabilities.
* (Historical note: HAL2 driver was first written by Ulf Carlsson - ALSA
* 0.3 running with 2.2.x kernel. Then ALSA changed completely and it
* seemed easier to me to write OSS driver from scratch - this one. Now
* when ALSA is official part of 2.6 kernel it's time to write ALSA driver
* using (hopefully) final version of ALSA interface)
*/
#define H2_BLOCK_SIZE 1024
#define H2_ADC_BUFSIZE 8192
#define H2_DAC_BUFSIZE 16834
struct hal2_pbus {
struct hpc3_pbus_dmacregs *pbus;
int pbusnr;
unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */
};
struct hal2_desc {
struct hpc_dma_desc desc;
u32 cnt; /* don't touch, it is also padding */
};
struct hal2_codec {
unsigned char *buffer;
struct hal2_desc *desc;
int desc_count;
int tail, head; /* tail index, head index */
struct hal2_pbus pbus;
unsigned int format; /* Audio data format */
int voices; /* mono/stereo */
unsigned int sample_rate;
unsigned int master; /* Master frequency */
unsigned short mod; /* MOD value */
unsigned short inc; /* INC value */
wait_queue_head_t dma_wait;
spinlock_t lock;
struct mutex sem;
int usecount; /* recording and playback are
* independent */
};
#define H2_MIX_OUTPUT_ATT 0
#define H2_MIX_INPUT_GAIN 1
#define H2_MIXERS 2
struct hal2_mixer {
int modcnt;
unsigned int master;
unsigned int volume[H2_MIXERS];
};
struct hal2_card {
int dev_dsp; /* audio device */
int dev_mixer; /* mixer device */
int dev_midi; /* midi device */
struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */
struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */
struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */
struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */
struct hal2_codec dac;
struct hal2_codec adc;
struct hal2_mixer mixer;
};
#define H2_INDIRECT_WAIT(regs) while (regs->isr & H2_ISR_TSTATUS);
#define H2_READ_ADDR(addr) (addr | (1<<7))
#define H2_WRITE_ADDR(addr) (addr)
static char *hal2str = "HAL2";
/*
* I doubt anyone has a machine with two HAL2 cards. It's possible to
* have two HPC's, so it is probably possible to have two HAL2 cards.
* Try to deal with it, but note that it is not tested.
*/
#define MAXCARDS 2
static struct hal2_card* hal2_card[MAXCARDS];
static const struct {
unsigned char idx:4, avail:1;
} mixtable[SOUND_MIXER_NRDEVICES] = {
[SOUND_MIXER_PCM] = { H2_MIX_OUTPUT_ATT, 1 }, /* voice */
[SOUND_MIXER_MIC] = { H2_MIX_INPUT_GAIN, 1 }, /* mic */
};
#define H2_SUPPORTED_FORMATS (AFMT_S16_LE | AFMT_S16_BE)
static inline void hal2_isr_write(struct hal2_card *hal2, u16 val)
{
hal2->ctl_regs->isr = val;
}
static inline u16 hal2_isr_look(struct hal2_card *hal2)
{
return hal2->ctl_regs->isr;
}
static inline u16 hal2_rev_look(struct hal2_card *hal2)
{
return hal2->ctl_regs->rev;
}
#ifdef HAL2_DUMP_REGS
static u16 hal2_i_look16(struct hal2_card *hal2, u16 addr)
{
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->iar = H2_READ_ADDR(addr);
H2_INDIRECT_WAIT(regs);
return regs->idr0;
}
#endif
static u32 hal2_i_look32(struct hal2_card *hal2, u16 addr)
{
u32 ret;
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->iar = H2_READ_ADDR(addr);
H2_INDIRECT_WAIT(regs);
ret = regs->idr0 & 0xffff;
regs->iar = H2_READ_ADDR(addr | 0x1);
H2_INDIRECT_WAIT(regs);
ret |= (regs->idr0 & 0xffff) << 16;
return ret;
}
static void hal2_i_write16(struct hal2_card *hal2, u16 addr, u16 val)
{
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->idr0 = val;
regs->idr1 = 0;
regs->idr2 = 0;
regs->idr3 = 0;
regs->iar = H2_WRITE_ADDR(addr);
H2_INDIRECT_WAIT(regs);
}
static void hal2_i_write32(struct hal2_card *hal2, u16 addr, u32 val)
{
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->idr0 = val & 0xffff;
regs->idr1 = val >> 16;
regs->idr2 = 0;
regs->idr3 = 0;
regs->iar = H2_WRITE_ADDR(addr);
H2_INDIRECT_WAIT(regs);
}
static void hal2_i_setbit16(struct hal2_card *hal2, u16 addr, u16 bit)
{
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->iar = H2_READ_ADDR(addr);
H2_INDIRECT_WAIT(regs);
regs->idr0 = (regs->idr0 & 0xffff) | bit;
regs->idr1 = 0;
regs->idr2 = 0;
regs->idr3 = 0;
regs->iar = H2_WRITE_ADDR(addr);
H2_INDIRECT_WAIT(regs);
}
static void hal2_i_setbit32(struct hal2_card *hal2, u16 addr, u32 bit)
{
u32 tmp;
struct hal2_ctl_regs *regs = hal2->ctl_regs;
regs->iar = H2_READ_ADDR(addr);
H2_INDIRECT_WAIT(regs);
tmp = (regs->idr0 & 0xffff) | (regs->idr1 << 16) | bit;
regs->idr0 = tmp & 0xffff;
regs->idr1 = tmp >> 16;
regs->idr2 = 0;
regs->idr3 = 0;
regs->iar = H2_WRITE_ADDR(addr);
H2_INDIRECT_WAIT(regs);
}
static void hal2
|