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

📄 pas2_pcm.c

📁 freebsd v4.4内核源码
💻 C
字号:
#define _PAS2_PCM_C_/* * sound/pas2_pcm.c * * The low level driver for the Pro Audio Spectrum ADC/DAC. * * Copyright by Hannu Savolainen 1993 * * 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. * */#include <i386/isa/sound/sound_config.h>#ifdef CONFIGURE_SOUNDCARD#include <i386/isa/sound/pas_defs.h>static int pcm_set_bits __P((int arg));static int pcm_set_channels __P((int arg));static int pcm_set_speed __P((int arg));#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)#define TRACE(WHAT)		/*				   * * * (WHAT)   */#define PAS_PCM_INTRBITS (0x08)/* * Sample buffer timer interrupt enable */#define PCM_NON	0#define PCM_DAC	1#define PCM_ADC	2static unsigned long pcm_speed = 0;	/* sampling rate */static unsigned char pcm_channels = 1;	/* channels (1 or 2) */static unsigned char pcm_bits = 8;	/* bits/sample (8 or 16) */static unsigned char pcm_filter = 0;	/* filter FLAG */static unsigned char pcm_mode = PCM_NON;static unsigned long pcm_count = 0;static unsigned short pcm_bitsok = 8;	/* mask of OK bits */static int      my_devnum = 0;static intpcm_set_speed (int arg){  int             foo, tmp;  unsigned long   flags;  if (arg > 44100)    arg = 44100;  if (arg < 5000)    arg = 5000;  foo = (1193180 + (arg / 2)) / arg;  arg = 1193180 / foo;  if (pcm_channels & 2)    foo = foo >> 1;  pcm_speed = arg;  tmp = pas_read (FILTER_FREQUENCY);  /*     * Set anti-aliasing filters according to sample rate. You reall *NEED*     * to enable this feature for all normal recording unless you want to     * experiment with aliasing effects.     * These filters apply to the selected "recording" source.     * I (pfw) don't know the encoding of these 5 bits. The values shown     * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.   */#if !defined NO_AUTO_FILTER_SET  tmp &= 0xe0;  if (pcm_speed >= 2 * 17897)    tmp |= 0x21;  else if (pcm_speed >= 2 * 15909)    tmp |= 0x22;  else if (pcm_speed >= 2 * 11931)    tmp |= 0x29;  else if (pcm_speed >= 2 * 8948)    tmp |= 0x31;  else if (pcm_speed >= 2 * 5965)    tmp |= 0x39;  else if (pcm_speed >= 2 * 2982)    tmp |= 0x24;  pcm_filter = tmp;#endif  DISABLE_INTR (flags);  pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);  pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);  pas_write (foo & 0xff, SAMPLE_RATE_TIMER);  pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);  pas_write (tmp, FILTER_FREQUENCY);  RESTORE_INTR (flags);  return pcm_speed;}static intpcm_set_channels (int arg){  if ((arg != 1) && (arg != 2))    return pcm_channels;  if (arg != pcm_channels)    {      pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);      pcm_channels = arg;      pcm_set_speed (pcm_speed);	/*					   * The speed must be reinitialized					 */    }  return pcm_channels;}static intpcm_set_bits (int arg){  if ((arg & pcm_bitsok) != arg)    return pcm_bits;  if (arg != pcm_bits)    {      pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);      pcm_bits = arg;    }  return pcm_bits;}static intpas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){  TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));  switch (cmd)    {    case SOUND_PCM_WRITE_RATE:      if (local)	return pcm_set_speed (arg);      return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));      break;    case SOUND_PCM_READ_RATE:      if (local)	return pcm_speed;      return IOCTL_OUT (arg, pcm_speed);      break;    case SNDCTL_DSP_STEREO:      if (local)	return pcm_set_channels (arg + 1) - 1;      return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);      break;    case SOUND_PCM_WRITE_CHANNELS:      if (local)	return pcm_set_channels (arg);      return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));      break;    case SOUND_PCM_READ_CHANNELS:      if (local)	return pcm_channels;      return IOCTL_OUT (arg, pcm_channels);      break;    case SNDCTL_DSP_SETFMT:      if (local)	return pcm_set_bits (arg);      return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));      break;    case SOUND_PCM_READ_BITS:      if (local)	return pcm_bits;      return IOCTL_OUT (arg, pcm_bits);    case SOUND_PCM_WRITE_FILTER:	/*					 * NOT YET IMPLEMENTED					 */      if (IOCTL_IN (arg) > 1)	return IOCTL_OUT (arg, RET_ERROR (EINVAL));      break;      pcm_filter = IOCTL_IN (arg);    case SOUND_PCM_READ_FILTER:      return IOCTL_OUT (arg, pcm_filter);      break;    default:      return RET_ERROR (EINVAL);    }  return RET_ERROR (EINVAL);}static voidpas_pcm_reset (int dev){  TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);}static intpas_pcm_open (int dev, int mode){  int             err;  TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));  if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)    return err;  if (DMAbuf_open_dma (dev) < 0)    {      pas_remove_intr (PAS_PCM_INTRBITS);      return RET_ERROR (EBUSY);    }  pcm_count = 0;  return 0;}static voidpas_pcm_close (int dev){  unsigned long   flags;  TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));  DISABLE_INTR (flags);  pas_pcm_reset (dev);  DMAbuf_close_dma (dev);  pas_remove_intr (PAS_PCM_INTRBITS);  pcm_mode = PCM_NON;  RESTORE_INTR (flags);}static voidpas_pcm_output_block (int dev, unsigned long buf, int count,		      int intrflag, int restart_dma){  unsigned long   flags, cnt;  TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));  cnt = count;  if (audio_devs[dev]->dmachan > 3)    cnt >>= 1;  if (audio_devs[dev]->flags & DMA_AUTOMODE &&      intrflag &&      cnt == pcm_count)    return;			/*				 * Auto mode on. No need to react				 */  DISABLE_INTR (flags);  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,	     PCM_CONTROL);  if (restart_dma)    DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);  if (audio_devs[dev]->dmachan > 3)    count >>= 1;  if (count != pcm_count)    {      pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);      pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);      pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);      pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);      pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);      pcm_count = count;    }  pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);  pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);  pcm_mode = PCM_DAC;  RESTORE_INTR (flags);}static voidpas_pcm_start_input (int dev, unsigned long buf, int count,		     int intrflag, int restart_dma){  unsigned long   flags;  int             cnt;  TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));  cnt = count;  if (audio_devs[dev]->dmachan > 3)    cnt >>= 1;  if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&      intrflag &&      cnt == pcm_count)    return;			/*				 * Auto mode on. No need to react				 */  DISABLE_INTR (flags);  if (restart_dma)    DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);  if (audio_devs[dev]->dmachan > 3)    count >>= 1;  if (count != pcm_count)    {      pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);      pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);      pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);      pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);      pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);      pcm_count = count;    }  pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);  pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);  pcm_mode = PCM_ADC;  RESTORE_INTR (flags);}static intpas_pcm_prepare_for_input (int dev, int bsize, int bcount){  return 0;}static intpas_pcm_prepare_for_output (int dev, int bsize, int bcount){  return 0;}static struct audio_operations pas_pcm_operations ={  "Pro Audio Spectrum",  DMA_AUTOMODE,  AFMT_U8 | AFMT_S16_LE,  NULL,  pas_pcm_open,  pas_pcm_close,  pas_pcm_output_block,  pas_pcm_start_input,  pas_pcm_ioctl,  pas_pcm_prepare_for_input,  pas_pcm_prepare_for_output,  pas_pcm_reset,  pas_pcm_reset,  NULL,  NULL};longpas_pcm_init (long mem_start, struct address_info *hw_config){  TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));  pcm_bitsok = 8;  if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)    pcm_bitsok |= 16;  pcm_set_speed (DSP_DEFAULT_SPEED);  if (num_audiodevs < MAX_AUDIO_DEV)    {      audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;      audio_devs[my_devnum]->dmachan = hw_config->dma;      audio_devs[my_devnum]->buffcount = 1;      audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE;    }  else    printk ("PAS2: Too many PCM devices available\n");  return mem_start;}voidpas_pcm_interrupt (unsigned char status, int cause){  if (cause == 1)		/*				 * PCM buffer done				 */    {      /*       * Halt the PCM first. Otherwise we don't have time to start a new       * block before the PCM chip proceeds to the next sample       */      if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))	{	  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,		     PCM_CONTROL);	}      switch (pcm_mode)	{	case PCM_DAC:	  DMAbuf_outputintr (my_devnum, 1);	  break;	case PCM_ADC:	  DMAbuf_inputintr (my_devnum);	  break;	default:	  printk ("PAS: Unexpected PCM interrupt\n");	}    }}#endif#endif

⌨️ 快捷键说明

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