📄 ad1848.c
字号:
/* * sound/ad1848.c * * The low level driver for the AD1848/CS4248 codec chip which * is used for example in the MS Sound System. * * The CS4231 which is used in the GUS MAX and some other cards is * upwards compatible with AD1848 and this driver is able to drive it. * * CS4231A and AD1845 are upward compatible with CS4231. However * the new features of these chips are different. * * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). * CS4232A is an improved version of CS4232. * * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * general sleep/wakeup clean up. * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free * of irqs. Use dev_id. * Christoph Hellwig : adapted to module_init/module_exit * Aki Laukkanen : added power management support * Arnaldo C. de Melo : added missing restore_flags in ad1848_resume * Miguel Freitas : added ISA PnP support * Alan Cox : Added CS4236->4239 identification * Daniel T. Cobra : Alernate config/mixer for later chips * Alan Cox : Merged chip idents and config code * * TODO * APM save restore assist code on IBM thinkpad * * Status: * Tested. Believed fully functional. */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/stddef.h>#include <linux/pm.h>#include <linux/isapnp.h>#define DEB(x)#define DEB1(x)#include "sound_config.h"#include "ad1848.h"#include "ad1848_mixer.h"typedef struct{ int base; int irq; int dma1, dma2; int dual_dma; /* 1, when two DMA channels allocated */ int subtype; unsigned char MCE_bit; unsigned char saved_regs[64]; /* Includes extended register space */ int debug_flag; int audio_flags; int record_dev, playback_dev; int xfer_count; int audio_mode; int open_mode; int intr_active; char *chip_name, *name; int model;#define MD_1848 1#define MD_4231 2#define MD_4231A 3#define MD_1845 4#define MD_4232 5#define MD_C930 6#define MD_IWAVE 7#define MD_4235 8 /* Crystal Audio CS4235 */#define MD_1845_SSCAPE 9 /* Ensoniq Soundscape PNP*/#define MD_4236 10 /* 4236 and higher */#define MD_42xB 11 /* CS 42xB */#define MD_4239 12 /* CS4239 */ /* Mixer parameters */ int recmask; int supported_devices, orig_devices; int supported_rec_devices, orig_rec_devices; int *levels; short mixer_reroute[32]; int dev_no; volatile unsigned long timer_ticks; int timer_running; int irq_ok; mixer_ents *mix_devices; int mixer_output_port; /* Power management */ struct pm_dev *pmdev;} ad1848_info;typedef struct ad1848_port_info{ int open_mode; int speed; unsigned char speed_bits; int channels; int audio_format; unsigned char format_bits;}ad1848_port_info;static struct address_info cfg;static int nr_ad1848_devs;int deskpro_xl;int deskpro_m;int soundpro;static volatile signed char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};#ifndef EXCLUDE_TIMERSstatic int timer_installed = -1;#endifstatic int loaded;static int ad_format_mask[13 /*devc->model */ ] ={ 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE /* CS4235 */, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM };static ad1848_info adev_info[MAX_AUDIO_DEV];#define io_Index_Addr(d) ((d)->base)#define io_Indexed_Data(d) ((d)->base+1)#define io_Status(d) ((d)->base+2)#define io_Polled_IO(d) ((d)->base+3)static struct { unsigned char flags;#define CAP_F_TIMER 0x01 } capabilities [10 /*devc->model */ ] = { {0} ,{0} /* MD_1848 */ ,{CAP_F_TIMER} /* MD_4231 */ ,{CAP_F_TIMER} /* MD_4231A */ ,{CAP_F_TIMER} /* MD_1845 */ ,{CAP_F_TIMER} /* MD_4232 */ ,{0} /* MD_C930 */ ,{CAP_F_TIMER} /* MD_IWAVE */ ,{0} /* MD_4235 */ ,{CAP_F_TIMER} /* MD_1845_SSCAPE */};#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstatic int isapnp = 1;static int isapnpjump = 0;static int reverse = 0;static int audio_activated = 0;#elsestatic int isapnp = 0;#endifstatic int ad1848_open(int dev, int mode);static void ad1848_close(int dev);static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag);static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag);static int ad1848_prepare_for_output(int dev, int bsize, int bcount);static int ad1848_prepare_for_input(int dev, int bsize, int bcount);static void ad1848_halt(int dev);static void ad1848_halt_input(int dev);static void ad1848_halt_output(int dev);static void ad1848_trigger(int dev, int bits);static int ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);#ifndef EXCLUDE_TIMERSstatic int ad1848_tmr_install(int dev);static void ad1848_tmr_reprogram(int dev);#endifstatic int ad_read(ad1848_info * devc, int reg){ unsigned long flags; int x; int timeout = 900000; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; save_flags(flags); cli(); if(reg < 32) { outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); x = inb(io_Indexed_Data(devc)); } else { int xreg, xra; xreg = (reg & 0xff) - 32; xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); x = inb(io_Indexed_Data(devc)); } restore_flags(flags); return x;}static void ad_write(ad1848_info * devc, int reg, int data){ unsigned long flags; int timeout = 900000; while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ timeout--; save_flags(flags); cli(); if(reg < 32) { outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc)); } else { int xreg, xra; xreg = (reg & 0xff) - 32; xra = (((xreg & 0x0f) << 4) & 0xf0) | 0x08 | ((xreg & 0x10) >> 2); outb(((unsigned char) (23 & 0xff) | devc->MCE_bit), io_Index_Addr(devc)); outb(((unsigned char) (xra & 0xff)), io_Indexed_Data(devc)); outb((unsigned char) (data & 0xff), io_Indexed_Data(devc)); } restore_flags(flags);}static void wait_for_calibration(ad1848_info * devc){ int timeout = 0; /* * Wait until the auto calibration process has finished. * * 1) Wait until the chip becomes ready (reads don't return 0x80). * 2) Wait until the ACI bit of I11 gets on and then off. */ timeout = 100000; while (timeout > 0 && inb(devc->base) == 0x80) timeout--; if (inb(devc->base) & 0x80) printk(KERN_WARNING "ad1848: Auto calibration timed out(1).\n"); timeout = 100; while (timeout > 0 && !(ad_read(devc, 11) & 0x20)) timeout--; if (!(ad_read(devc, 11) & 0x20)) return; timeout = 80000; while (timeout > 0 && (ad_read(devc, 11) & 0x20)) timeout--; if (ad_read(devc, 11) & 0x20) if ( (devc->model != MD_1845) || (devc->model != MD_1845_SSCAPE)) printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n");}static void ad_mute(ad1848_info * devc){ int i; unsigned char prev; /* * Save old register settings and mute output channels */ for (i = 6; i < 8; i++) { prev = devc->saved_regs[i] = ad_read(devc, i); }}static void ad_unmute(ad1848_info * devc){}static void ad_enter_MCE(ad1848_info * devc){ unsigned long flags; int timeout = 1000; unsigned short prev; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; save_flags(flags); cli(); devc->MCE_bit = 0x40; prev = inb(io_Index_Addr(devc)); if (prev & 0x40) { restore_flags(flags); return; } outb((devc->MCE_bit), io_Index_Addr(devc)); restore_flags(flags);}static void ad_leave_MCE(ad1848_info * devc){ unsigned long flags; unsigned char prev, acal; int timeout = 1000; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; save_flags(flags); cli(); acal = ad_read(devc, 9); devc->MCE_bit = 0x00; prev = inb(io_Index_Addr(devc)); outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ if ((prev & 0x40) == 0) /* Not in MCE mode */ { restore_flags(flags); return; } outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ if (acal & 0x08) /* Auto calibration is enabled */ wait_for_calibration(devc); restore_flags(flags);}static int ad1848_set_recmask(ad1848_info * devc, int mask){ unsigned char recdev; int i, n; mask &= devc->supported_rec_devices; /* Rename the mixer bits if necessary */ for (i = 0; i < 32; i++) { if (devc->mixer_reroute[i] != i) { if (mask & (1 << i)) { mask &= ~(1 << i); mask |= (1 << devc->mixer_reroute[i]); } } } n = 0; for (i = 0; i < 32; i++) /* Count selected device bits */ if (mask & (1 << i)) n++; if (!soundpro) { if (n == 0) mask = SOUND_MASK_MIC; else if (n != 1) { /* Too many devices selected */ mask &= ~devc->recmask; /* Filter out active settings */ n = 0; for (i = 0; i < 32; i++) /* Count selected device bits */ if (mask & (1 << i)) n++; if (n != 1) mask = SOUND_MASK_MIC; } switch (mask) { case SOUND_MASK_MIC: recdev = 2; break; case SOUND_MASK_LINE: case SOUND_MASK_LINE3: recdev = 0; break; case SOUND_MASK_CD: case SOUND_MASK_LINE1: recdev = 1; break; case SOUND_MASK_IMIX: recdev = 3; break; default: mask = SOUND_MASK_MIC; recdev = 2; } recdev <<= 6; ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); } else { /* soundpro */ unsigned char val; int set_rec_bit; int j; for (i = 0; i < 32; i++) { /* For each bit */ if ((devc->supported_rec_devices & (1 << i)) == 0) continue; /* Device not supported */ for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ continue; /* * This is tricky: * set_rec_bit becomes 1 if the corresponding bit in mask is set * then it gets flipped if the polarity is inverse */ set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; val = ad_read(devc, devc->mix_devices[i][j].recreg); val &= ~(1 << devc->mix_devices[i][j].recpos); val |= (set_rec_bit << devc->mix_devices[i][j].recpos); ad_write(devc, devc->mix_devices[i][j].recreg, val); } } } /* Rename the mixer bits back if necessary */ for (i = 0; i < 32; i++) { if (devc->mixer_reroute[i] != i) { if (mask & (1 << devc->mixer_reroute[i])) { mask &= ~(1 << devc->mixer_reroute[i]); mask |= (1 << i); } } } devc->recmask = mask; return mask;}static void change_bits(ad1848_info * devc, unsigned char *regval, unsigned char *muteval, int dev, int chn, int newval){ unsigned char mask; int shift; int mute; int mutemask; int set_mute_bit; set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ newval = 100 - newval; mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; shift = devc->mix_devices[dev][chn].bitpos; if (devc->mix_devices[dev][chn].mutepos == 8) { /* if there is no mute bit */ mute = 0; /* No mute bit; do nothing special */ mutemask = ~0; /* No mute bit; do nothing special */ } else { mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); } newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ *regval &= ~(mask << shift); /* Clear bits */ *regval |= (newval & mask) << shift; /* Set new value */ *muteval &= mutemask; *muteval |= mute;}static int ad1848_mixer_get(ad1848_info * devc, int dev){ if (!((1 << dev) & devc->supported_devices)) return -EINVAL; dev = devc->mixer_reroute[dev]; return devc->levels[dev];}static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel){ int regoffs, muteregoffs; unsigned char val, muteval; regoffs = devc->mix_devices[dev][channel].regno; muteregoffs = devc->mix_devices[dev][channel].mutereg; val = ad_read(devc, regoffs); if (muteregoffs != regoffs) { muteval = ad_read(devc, muteregoffs); change_bits(devc, &val, &muteval, dev, channel, value); } else change_bits(devc, &val, &val, dev, channel, value); ad_write(devc, regoffs, val); devc->saved_regs[regoffs] = val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -