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

📄 ad1848.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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. * * Copyright by Hannu Savolainen 1994, 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Modified: *  Riccardo Facchetti  24 Mar 1995 *  - Added the Audio Excel DSP 16 initialization routine. */#define DEB(x)#define DEB1(x)#include <i386/isa/sound/sound_config.h>#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)#include <i386/isa/sound/ad1848_mixer.h>#define IMODE_NONE		0#define IMODE_OUTPUT		1#define IMODE_INPUT		2#define IMODE_INIT		3#define IMODE_MIDI		4typedef struct  {    int             base;    int             irq;    int             dma_capture, dma_playback;    unsigned char   MCE_bit;    unsigned char   saved_regs[16];    int             speed;    unsigned char   speed_bits;    int             channels;    int             audio_format;    unsigned char   format_bits;    int             xfer_count;    int             irq_mode;    int             intr_active;    int             opened;    char           *chip_name;    int             mode;    /* Mixer parameters */    int             recmask;    int             supported_devices;    int             supported_rec_devices;    unsigned short  levels[32];  }ad1848_info;static int      nr_ad1848_devs = 0;static char     irq2dev[16] ={-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};static char     mixer2codec[MAX_MIXER_DEV] ={0};static int      ad_format_mask[3 /*devc->mode */ ] ={  0,  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM};static ad1848_info dev_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 int      ad1848_open (int dev, int mode);static void     ad1848_close (int dev);static int      ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);static void     ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);static void     ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);static int      ad1848_prepare_for_IO (int dev, int bsize, int bcount);static void     ad1848_reset (int dev);static void     ad1848_halt (int dev);static intad_read (ad1848_info * devc, int reg){  unsigned long   flags;  int             x;  int             timeout = 100;  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */    timeout--;  DISABLE_INTR (flags);  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));  x = INB (io_Indexed_Data (devc));  /*  printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */  RESTORE_INTR (flags);  return x;}static voidad_write (ad1848_info * devc, int reg, int data){  unsigned long   flags;  int             timeout = 100;  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */    timeout--;  DISABLE_INTR (flags);  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));  OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));  /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */  RESTORE_INTR (flags);}static voidwait_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;#ifdef PC98  while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)    timeout--;  if ((INB (devc->base) & 0x80) == 0x80)#else  while (timeout > 0 && INB (devc->base) & 0x80)    timeout--;  if (INB (devc->base) & 0x80)#endif    printk ("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 = 10000;  while (timeout > 0 && ad_read (devc, 11) & 0x20)    timeout--;  if (ad_read (devc, 11) & 0x20)    printk ("ad1848: Auto calibration timed out(3).\n");}static voidad_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);      ad_write (devc, i, prev | 0x80);    }}static voidad_unmute (ad1848_info * devc){  int             i;  /*     * Restore back old volume registers (unmute)   */  for (i = 6; i < 8; i++)    {      ad_write (devc, i, devc->saved_regs[i] & ~0x80);    }}static voidad_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--;  DISABLE_INTR (flags);  devc->MCE_bit = 0x40;  prev = INB (io_Index_Addr (devc));  if (prev & 0x40)    {      RESTORE_INTR (flags);      return;    }  OUTB (devc->MCE_bit, io_Index_Addr (devc));  RESTORE_INTR (flags);}static voidad_leave_MCE (ad1848_info * devc){  unsigned long   flags;  unsigned char   prev;  int             timeout = 1000;  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */    timeout--;  DISABLE_INTR (flags);  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_INTR (flags);      return;    }  OUTB (0x00, io_Index_Addr (devc));	/* Clear the MCE bit */  wait_for_calibration (devc);  RESTORE_INTR (flags);}static intad1848_set_recmask (ad1848_info * devc, int mask){  unsigned char   recdev;  int             i, n;  mask &= devc->supported_rec_devices;  n = 0;  for (i = 0; i < 32; i++)	/* Count selected device bits */    if (mask & (1 << i))      n++;  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;    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);  devc->recmask = mask;  return mask;}static voidchange_bits (unsigned char *regval, int dev, int chn, int newval){  unsigned char   mask;  int             shift;  if (mix_devices[dev][chn].polarity == 1)	/* Reverse */    newval = 100 - newval;  mask = (1 << mix_devices[dev][chn].nbits) - 1;  shift = mix_devices[dev][chn].bitpos;  newval = (int) ((newval * mask) + 50) / 100;	/* Scale it */  *regval &= ~(mask << shift);	/* Clear bits */  *regval |= (newval & mask) << shift;	/* Set new value */}static intad1848_mixer_get (ad1848_info * devc, int dev){  if (!((1 << dev) & devc->supported_devices))    return RET_ERROR (EINVAL);  return devc->levels[dev];}static intad1848_mixer_set (ad1848_info * devc, int dev, int value){  int             left = value & 0x000000ff;  int             right = (value & 0x0000ff00) >> 8;  int             regoffs;  unsigned char   val;  if (left > 100)    left = 100;  if (right > 100)    right = 100;  if (dev > 31)    return RET_ERROR (EINVAL);  if (!(devc->supported_devices & (1 << dev)))    return RET_ERROR (EINVAL);  if (mix_devices[dev][LEFT_CHN].nbits == 0)    return RET_ERROR (EINVAL);  /*     * Set the left channel   */  regoffs = mix_devices[dev][LEFT_CHN].regno;  val = ad_read (devc, regoffs);  change_bits (&val, dev, LEFT_CHN, left);  devc->levels[dev] = left | (left << 8);  ad_write (devc, regoffs, val);  devc->saved_regs[regoffs] = val;  /*     * Set the left right   */  if (mix_devices[dev][RIGHT_CHN].nbits == 0)    return left | (left << 8);	/* Was just a mono channel */  regoffs = mix_devices[dev][RIGHT_CHN].regno;  val = ad_read (devc, regoffs);  change_bits (&val, dev, RIGHT_CHN, right);  ad_write (devc, regoffs, val);  devc->saved_regs[regoffs] = val;  devc->levels[dev] = left | (right << 8);  return left | (right << 8);}static voidad1848_mixer_reset (ad1848_info * devc){  int             i;  devc->recmask = 0;  if (devc->mode == 2)    devc->supported_devices = MODE2_MIXER_DEVICES;  else    devc->supported_devices = MODE1_MIXER_DEVICES;  devc->supported_rec_devices = MODE1_REC_DEVICES;  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)    ad1848_mixer_set (devc, i, devc->levels[i] = default_mixer_levels[i]);  ad1848_set_recmask (devc, SOUND_MASK_MIC);}static intad1848_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg){  ad1848_info    *devc;  int             codec_dev = mixer2codec[dev];  if (!codec_dev)    return RET_ERROR (ENXIO);  codec_dev--;  devc = (ad1848_info *) audio_devs[codec_dev]->devc;  if (((cmd >> 8) & 0xff) == 'M')    {      if (cmd & IOC_IN)	switch (cmd & 0xff)	  {	  case SOUND_MIXER_RECSRC:	    return IOCTL_OUT (arg, ad1848_set_recmask (devc, IOCTL_IN (arg)));	    break;	  default:	    return IOCTL_OUT (arg, ad1848_mixer_set (devc, cmd & 0xff, IOCTL_IN (arg)));	  }      else	switch (cmd & 0xff)	/*				 * Return parameters				 */	  {	  case SOUND_MIXER_RECSRC:	    return IOCTL_OUT (arg, devc->recmask);	    break;	  case SOUND_MIXER_DEVMASK:	    return IOCTL_OUT (arg, devc->supported_devices);	    break;	  case SOUND_MIXER_STEREODEVS:	    return IOCTL_OUT (arg, devc->supported_devices &			      ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));	    break;	  case SOUND_MIXER_RECMASK:	    return IOCTL_OUT (arg, devc->supported_rec_devices);	    break;	  case SOUND_MIXER_CAPS:	    return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);	    break;	  default:	    return IOCTL_OUT (arg, ad1848_mixer_get (devc, cmd & 0xff));	  }    }  else    return RET_ERROR (EINVAL);}static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] ={  {    "Generic AD1848 codec",    DMA_AUTOMODE,    AFMT_U8,			/* Will be set later */    NULL,    ad1848_open,    ad1848_close,    ad1848_output_block,    ad1848_start_input,    ad1848_ioctl,    ad1848_prepare_for_IO,    ad1848_prepare_for_IO,    ad1848_reset,    ad1848_halt,    NULL,    NULL  }};static struct mixer_operations ad1848_mixer_operations ={  "AD1848/CS4248/CS4231",  ad1848_mixer_ioctl};static intad1848_open (int dev, int mode){  int             err;  ad1848_info    *devc = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -