📄 cs4231.c
字号:
/* $Id: cs4231.c,v 1.43 2000/02/18 13:49:39 davem Exp $ * drivers/sbus/audio/cs4231.c * * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) * The 4231/ebus support was written by David Miller, who didn't bother * crediting himself here, so I will. * * Based on the AMD7930 driver: * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) * * This is the lowlevel driver for the CS4231 audio chip found on some * sun4m and sun4u machines. * * This was culled from the Crystal docs on the 4231a, and the addendum they * faxed me on the 4231. * The APC DMA controller support unfortunately is not documented. Thanks, Sun. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/malloc.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/soundcard.h>#include <linux/version.h>#include <linux/ioport.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/sbus.h>#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff && defined(CONFIG_PCI)#define EB4231_SUPPORT#include <asm/ebus.h>#include <asm/pbm.h>#endif#include <asm/audioio.h>#include "cs4231.h"#undef __CS4231_DEBUG#undef __CS4231_TRACE#define __CS4231_ERROR#ifdef __CS4231_ERROR#define eprintk(x) printk x#else#define eprintk(x)#endif#ifdef __CS4231_TRACE#define tprintk(x) printk x#else#define tprintk(x)#endif#ifdef __CS4231_DEBUG#define dprintk(x) printk x#else#define dprintk(x)#endif#define MAX_DRIVERS 1static struct sparcaudio_driver drivers[MAX_DRIVERS];static int num_drivers;static int cs4231_record_gain(struct sparcaudio_driver *drv, int value, unsigned char balance);static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, unsigned char balance);static void cs4231_ready(struct sparcaudio_driver *drv);static void cs4231_playintr(struct sparcaudio_driver *drv, int);static int cs4231_recintr(struct sparcaudio_driver *drv);static int cs4231_output_muted(struct sparcaudio_driver *drv, int value);static void cs4231_pollinput(struct sparcaudio_driver *drv);static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir, unsigned int length);static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int value);#ifdef EB4231_SUPPORTstatic void eb4231_pollinput(struct sparcaudio_driver *drv);#endif/* Serveral shorthands save typing... */#define CHIP_READY() \do { udelay(100); cs4231_ready(drv); udelay(1000); } while(0)#define WRITE_IAR(__VAL) \ CS4231_WRITE8(cs4231_chip, cs4231_chip->regs + IAR, __VAL)#define WRITE_IDR(__VAL) \ CS4231_WRITE8(cs4231_chip, cs4231_chip->regs + IDR, __VAL)#define READ_IAR() \ CS4231_READ8(cs4231_chip, cs4231_chip->regs + IAR)#define READ_IDR() \ CS4231_READ8(cs4231_chip, cs4231_chip->regs + IDR)/* Enable cs4231 interrupts atomically. */static void cs4231_enable_interrupts(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("enabling interrupts\n")); save_flags(flags); cli(); if ((cs4231_chip->status & CS_STATUS_INTS_ON) == 0) { WRITE_IAR(0xa); WRITE_IDR(INTR_ON); cs4231_chip->status |= CS_STATUS_INTS_ON; } restore_flags(flags);}/* Disable cs4231 interrupts atomically. */static void cs4231_disable_interrupts(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("disabling interrupts\n")); save_flags(flags); cli(); if ((cs4231_chip->status & CS_STATUS_INTS_ON) != 0) { WRITE_IAR(0xa); WRITE_IDR(INTR_OFF); cs4231_chip->status &= ~CS_STATUS_INTS_ON; } restore_flags(flags);}static void cs4231_enable_play(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("enabling play\n")); save_flags(flags); cli(); WRITE_IAR(0x9); WRITE_IDR(READ_IDR() | PEN_ENABLE); restore_flags(flags);}static void cs4231_disable_play(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("disabling play\n")); save_flags(flags); cli(); WRITE_IAR(0x9); WRITE_IDR(READ_IDR() & PEN_DISABLE); restore_flags(flags);}static void cs4231_enable_rec(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("enabling rec\n")); save_flags(flags); cli(); WRITE_IAR(0x9); WRITE_IDR(READ_IDR() | CEN_ENABLE); restore_flags(flags);}static void cs4231_disable_rec(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; unsigned long flags; tprintk(("disabling rec\n")); save_flags(flags); cli(); WRITE_IAR(0x9); WRITE_IDR(READ_IDR() & CEN_DISABLE); restore_flags(flags);}static struct cs4231_rates { int speed, bits;} cs4231_rate_table[] = { { 5512, CS4231_DFR_5512 }, { 6615, CS4231_DFR_6615 }, { 8000, CS4231_DFR_8000 }, { 9600, CS4231_DFR_9600 }, { 11025, CS4231_DFR_11025 }, { 16000, CS4231_DFR_16000 }, { 18900, CS4231_DFR_18900 }, { 22050, CS4231_DFR_22050 }, { 27429, CS4231_DFR_27429 }, { 32000, CS4231_DFR_32000 }, { 33075, CS4231_DFR_33075 }, { 37800, CS4231_DFR_37800 }, { 44100, CS4231_DFR_44100 }, { 48000, CS4231_DFR_48000 }};#define NUM_RATES (sizeof(cs4231_rate_table) / sizeof(struct cs4231_rates))static int cs4231_rate_to_bits(struct sparcaudio_driver *drv, int *value){ struct cs4231_rates *p = &cs4231_rate_table[0]; int i, wanted = *value; /* We try to be nice and approximate what the user asks for. */ if (wanted < 5512) wanted = 5512; if (wanted > 48000) wanted = 48000; for (i = 0; i < NUM_RATES; i++, p++) { /* Exact match? */ if (wanted == p->speed) break; /* If we're inbetween two entries, and neither is exact, * pick the closest one. */ if (wanted == p[1].speed) continue; if (wanted > p->speed && wanted < p[1].speed) { int diff1, diff2; diff1 = wanted - p->speed; diff2 = p[1].speed - wanted; if (diff2 < diff1) p++; break; } } *value = p->speed; return p->bits;}static int cs4231_encoding_to_bits(struct sparcaudio_driver *drv, int value){ int set_bits; switch (value) { case AUDIO_ENCODING_ULAW: set_bits = CS4231_DFR_ULAW; break; case AUDIO_ENCODING_ALAW: set_bits = CS4231_DFR_ALAW; break; case AUDIO_ENCODING_DVI: set_bits = CS4231_DFR_ADPCM; break; case AUDIO_ENCODING_LINEARLE: set_bits = CS4231_DFR_LINEARLE; break; case AUDIO_ENCODING_LINEAR: set_bits = CS4231_DFR_LINEARBE; break; case AUDIO_ENCODING_LINEAR8: set_bits = CS4231_DFR_LINEAR8; break; default: set_bits = -EINVAL; break; }; return set_bits;}static int cs4231_set_output_encoding(struct sparcaudio_driver *drv, int value){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; int tmp_bits, set_bits; tprintk(("output encoding %d\n", value)); if (value != 0) { set_bits = cs4231_encoding_to_bits(drv, value); if (set_bits >= 0) { READ_IDR(); READ_IDR(); WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x8); tmp_bits = READ_IDR(); WRITE_IDR(CHANGE_ENCODING(tmp_bits, set_bits)); READ_IDR(); READ_IDR(); CHIP_READY(); cs4231_chip->perchip_info.play.encoding = value; return 0; } } dprintk(("output enc failed\n")); return -EINVAL;}static int cs4231_get_output_encoding(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; return cs4231_chip->perchip_info.play.encoding;}static int cs4231_set_input_encoding(struct sparcaudio_driver *drv, int value){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; int tmp_bits, set_bits; tprintk(("input encoding %d\n", value)); if (value != 0) { set_bits = cs4231_encoding_to_bits(drv, value); if (set_bits >= 0) { READ_IDR(); READ_IDR(); WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x1c); tmp_bits = READ_IDR(); WRITE_IDR(CHANGE_ENCODING(tmp_bits, set_bits)); READ_IDR(); READ_IDR(); CHIP_READY(); cs4231_chip->perchip_info.record.encoding = value; return 0; } } dprintk(("input enc failed\n")); return -EINVAL;}static int cs4231_get_input_encoding(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; return cs4231_chip->perchip_info.record.encoding;}static int cs4231_set_output_rate(struct sparcaudio_driver *drv, int value){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; int tmp_bits, set_bits; tprintk(("output rate %d\n", value)); if (value != 0) { set_bits = cs4231_rate_to_bits(drv, &value); if (set_bits >= 0) { READ_IDR(); READ_IDR(); WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x8); tmp_bits = READ_IDR(); WRITE_IDR(CHANGE_DFR(tmp_bits, set_bits)); READ_IDR(); READ_IDR(); CHIP_READY(); cs4231_chip->perchip_info.play.sample_rate = value; tprintk(("tmp_bits[%02x] set_bits[%02x] CHANGE_DFR[%02x]\n", tmp_bits, set_bits, CHANGE_DFR(tmp_bits, set_bits))); return 0; } } dprintk(("output rate failed\n")); return -EINVAL;}static int cs4231_get_output_rate(struct sparcaudio_driver *drv){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; return cs4231_chip->perchip_info.play.sample_rate;}static int cs4231_set_input_rate(struct sparcaudio_driver *drv, int value){ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; int tmp_bits, set_bits; tprintk(("input rate %d\n", value)); if (value != 0) { set_bits = cs4231_rate_to_bits(drv, &value); if (set_bits >= 0) { READ_IDR();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -