📄 ad1848.c
字号:
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 + -