⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs4231.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $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 + -