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

📄 ad1848.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  unsigned long   flags;  DEB (printk ("ad1848_open(int mode = %X)\n", mode));  if (dev < 0 || dev >= num_audiodevs)    return RET_ERROR (ENXIO);  devc = (ad1848_info *) audio_devs[dev]->devc;  DISABLE_INTR (flags);  if (devc->opened)    {      RESTORE_INTR (flags);      printk ("ad1848: Already opened\n");      return RET_ERROR (EBUSY);    }  if (devc->irq)		/* Not managed by another driver */    if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt,				    audio_devs[dev]->name)) < 0)      {	printk ("ad1848: IRQ in use\n");	RESTORE_INTR (flags);	return err;      }  if (DMAbuf_open_dma (dev) < 0)    {      RESTORE_INTR (flags);      printk ("ad1848: DMA in use\n");      return RET_ERROR (EBUSY);    }  devc->intr_active = 0;  devc->opened = 1;  RESTORE_INTR (flags);  return 0;}static voidad1848_close (int dev){  unsigned long   flags;  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  DEB (printk ("ad1848_close(void)\n"));  DISABLE_INTR (flags);  devc->intr_active = 0;  if (devc->irq)		/* Not managed by another driver */    snd_release_irq (devc->irq);  ad1848_reset (dev);  DMAbuf_close_dma (dev);  devc->opened = 0;  RESTORE_INTR (flags);}static intset_speed (ad1848_info * devc, int arg){  /*     * The sampling speed is encoded in the least significant nible of I8. The     * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other     * three bits select the divisor (indirectly):     *     * The available speeds are in the following table. Keep the speeds in     * the increasing order.   */  typedef struct  {    int             speed;    unsigned char   bits;  }  speed_struct;  static speed_struct speed_table[] =  {    {5510, (0 << 1) | 1},    {5510, (0 << 1) | 1},    {6620, (7 << 1) | 1},    {8000, (0 << 1) | 0},    {9600, (7 << 1) | 0},    {11025, (1 << 1) | 1},    {16000, (1 << 1) | 0},    {18900, (2 << 1) | 1},    {22050, (3 << 1) | 1},    {27420, (2 << 1) | 0},    {32000, (3 << 1) | 0},    {33075, (6 << 1) | 1},    {37800, (4 << 1) | 1},    {44100, (5 << 1) | 1},    {48000, (6 << 1) | 0}  };  int             i, n, selected = -1;  n = sizeof (speed_table) / sizeof (speed_struct);  if (arg < speed_table[0].speed)    selected = 0;  if (arg > speed_table[n - 1].speed)    selected = n - 1;  for (i = 1 /*really */ ; selected == -1 && i < n; i++)    if (speed_table[i].speed == arg)      selected = i;    else if (speed_table[i].speed > arg)      {	int             diff1, diff2;	diff1 = arg - speed_table[i - 1].speed;	diff2 = speed_table[i].speed - arg;	if (diff1 < diff2)	  selected = i - 1;	else	  selected = i;      }  if (selected == -1)    {      printk ("ad1848: Can't find speed???\n");      selected = 3;    }  devc->speed = speed_table[selected].speed;  devc->speed_bits = speed_table[selected].bits;  return devc->speed;}static intset_channels (ad1848_info * devc, int arg){  if (arg != 1 && arg != 2)    return devc->channels;  devc->channels = arg;  return arg;}static intset_format (ad1848_info * devc, int arg){  static struct format_tbl  {    int             format;    unsigned char   bits;  }  format2bits[] =  {    {      0, 0    }    ,    {      AFMT_MU_LAW, 1    }    ,    {      AFMT_A_LAW, 3    }    ,    {      AFMT_IMA_ADPCM, 5    }    ,    {      AFMT_U8, 0    }    ,    {      AFMT_S16_LE, 2    }    ,    {      AFMT_S16_BE, 6    }    ,    {      AFMT_S8, 0    }    ,    {      AFMT_U16_LE, 0    }    ,    {      AFMT_U16_BE, 0    }  };  int             i, n = sizeof (format2bits) / sizeof (struct format_tbl);  if (!(arg & ad_format_mask[devc->mode]))    arg = AFMT_U8;  devc->audio_format = arg;  for (i = 0; i < n; i++)    if (format2bits[i].format == arg)      {	if ((devc->format_bits = format2bits[i].bits) == 0)	  return devc->audio_format = AFMT_U8;	/* Was not supported */	return arg;      }  /* Still hanging here. Something must be terribly wrong */  devc->format_bits = 0;  return devc->audio_format = AFMT_U8;}static intad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  switch (cmd)    {    case SOUND_PCM_WRITE_RATE:      if (local)	return set_speed (devc, arg);      return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));    case SOUND_PCM_READ_RATE:      if (local)	return devc->speed;      return IOCTL_OUT (arg, devc->speed);    case SNDCTL_DSP_STEREO:      if (local)	return set_channels (devc, arg + 1) - 1;      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);    case SOUND_PCM_WRITE_CHANNELS:      if (local)	return set_channels (devc, arg);      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));    case SOUND_PCM_READ_CHANNELS:      if (local)	return devc->channels;      return IOCTL_OUT (arg, devc->channels);    case SNDCTL_DSP_SAMPLESIZE:      if (local)	return set_format (devc, arg);      return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));    case SOUND_PCM_READ_BITS:      if (local)	return devc->audio_format;      return IOCTL_OUT (arg, devc->audio_format);    default:;    }  return RET_ERROR (EINVAL);}static voidad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart){  unsigned long   flags, cnt;  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  cnt = count;  if (devc->audio_format == AFMT_IMA_ADPCM)    {      cnt /= 4;    }  else    {      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */	cnt >>= 1;    }  if (devc->channels > 1)    cnt >>= 1;  cnt--;  if (audio_devs[dev]->flags & DMA_AUTOMODE &&      intrflag &&      cnt == devc->xfer_count)    {      devc->irq_mode = IMODE_OUTPUT;      devc->intr_active = 1;      return;			/*				 * Auto DMA mode on. No need to react				 */    }  DISABLE_INTR (flags);  if (dma_restart)    {      /* ad1848_halt (dev); */      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);    }  ad_enter_MCE (devc);  ad_write (devc, 15, (unsigned char) (cnt & 0xff));  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));  ad_write (devc, 9, 0x0d);	/*				 * Playback enable, single DMA channel mode,				 * auto calibration on.				 */  ad_leave_MCE (devc);		/*				 * Starts the calibration process and				 * enters playback mode after it.				 */  ad_unmute (devc);  devc->xfer_count = cnt;  devc->irq_mode = IMODE_OUTPUT;  devc->intr_active = 1;  INB (io_Status (devc));  OUTB (0, io_Status (devc));	/* Clear pending interrupts */  RESTORE_INTR (flags);}static voidad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart){  unsigned long   flags, cnt;  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  int             count_reg = 14;	/* (devc->mode == 1) ? 14 : 30; */  cnt = count;  if (devc->audio_format == AFMT_IMA_ADPCM)    {      cnt /= 4;    }  else    {      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */	cnt >>= 1;    }  if (devc->channels > 1)    cnt >>= 1;  cnt--;  if (audio_devs[dev]->flags & DMA_AUTOMODE &&      intrflag &&      cnt == devc->xfer_count)    {      devc->irq_mode = IMODE_INPUT;      devc->intr_active = 1;      return;			/*				 * Auto DMA mode on. No need to react				 */    }  DISABLE_INTR (flags);  if (dma_restart)    {      /* ad1848_halt (dev); */      DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);    }  ad_enter_MCE (devc);  ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));  ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));  ad_write (devc, 9, 0x0e);	/*				 * Capture enable, single DMA channel mode,				 * auto calibration on.				 */  ad_leave_MCE (devc);		/*				 * Starts the calibration process and				 * enters playback mode after it.				 */  ad_unmute (devc);  devc->xfer_count = cnt;  devc->irq_mode = IMODE_INPUT;  devc->intr_active = 1;  INB (io_Status (devc));  OUTB (0, io_Status (devc));	/* Clear interrupt status */  RESTORE_INTR (flags);}static intad1848_prepare_for_IO (int dev, int bsize, int bcount){  int             timeout;  unsigned char   fs;  unsigned long   flags;  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  DISABLE_INTR (flags);  ad_enter_MCE (devc);		/* Enables changes to the format select reg */  fs = devc->speed_bits | (devc->format_bits << 5);  if (devc->channels > 1)    fs |= 0x10;  ad_write (devc, 8, fs);  /*   * Write to I8 starts resyncronization. Wait until it completes.   */  timeout = 10000;#ifdef PC98  while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)#else  while (timeout > 0 && INB (devc->base) == 0x80)#endif    timeout--;#ifdef PC98  ad_write (devc, 8, fs);  /*   * Write to I8 starts resyncronization. Wait until it completes.   */  timeout = 10000;  while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)    timeout--;#endif  /*     * If mode == 2 (CS4231), set I28 also. It's the capture format register.   */  if (devc->mode == 2)    {      ad_write (devc, 28, fs);      /*         * Write to I28 starts resyncronization. Wait until it completes.       */      timeout = 10000;#ifdef PC98      while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)#else      while (timeout > 0 && INB (devc->base) == 0x80)#endif	timeout--;    }#ifdef PC98      ad_write (devc, 28, fs);      /*         * Write to I28 starts resyncronization. Wait until it completes.       */      timeout = 10000;      while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)	timeout--;#endif  ad_leave_MCE (devc);		/*				 * Starts the calibration process and				 * enters playback mode after it.				 */  RESTORE_INTR (flags);  devc->xfer_count = 0;  return 0;}static voidad1848_reset (int dev){  ad1848_halt (dev);}static voidad1848_halt (int dev){  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;  ad_mute (devc);#ifdef PC98  ad_enter_MCE (devc);#endif  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */#ifdef PC98  ad_leave_MCE (devc);#endif  OUTB (0, io_Status (devc));	/* Clear interrupt status */  ad_enter_MCE (devc);  OUTB (0, io_Status (devc));	/* Clear interrupt status */  ad_write (devc, 15, 0);	/* Clear DMA counter */  ad_write (devc, 14, 0);	/* Clear DMA counter */  if (devc->mode == 2)    {      ad_write (devc, 30, 0);	/* Clear DMA counter */      ad_write (devc, 31, 0);	/* Clear DMA counter */    }  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */  OUTB (0, io_Status (devc));	/* Clear interrupt status */  OUTB (0, io_Status (devc));	/* Clear interrupt status */  ad_leave_MCE (devc);  DMAbuf_reset_dma (dev);}intad1848_detect (int io_base)

⌨️ 快捷键说明

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