📄 opti92x-ad1848.c
字号:
case 5: irq_bits = 0x05; break;//#endif /* OPTi93X */ case 7: irq_bits = 0x01; break; case 9: irq_bits = 0x02; break; case 10: irq_bits = 0x03; break; case 11: irq_bits = 0x04; break; default: snd_printk("WSS irq # %d not valid\n", chip->irq); goto __skip_resources; } switch (chip->dma1) { case 0: dma_bits = 0x01; break; case 1: dma_bits = 0x02; break; case 3: dma_bits = 0x03; break; default: snd_printk("WSS dma1 # %d not valid\n", chip->dma1); goto __skip_resources; }#if defined(CS4231) || defined(OPTi93X) if (chip->dma1 == chip->dma2) { snd_printk("don't want to share dmas\n"); return -EBUSY; } switch (chip->dma2) { case 0: case 1: break; default: snd_printk("WSS dma2 # %d not valid\n", chip->dma2); goto __skip_resources; } dma_bits |= 0x04;#endif /* CS4231 || OPTi93X */#ifndef OPTi93X outb(irq_bits << 3 | dma_bits, chip->wss_base);#else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));#endif /* OPTi93X */__skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { switch (chip->mpu_port) { case 0: case -1: break; case 0x300: mpu_port_bits = 0x03; break; case 0x310: mpu_port_bits = 0x02; break; case 0x320: mpu_port_bits = 0x01; break; case 0x330: mpu_port_bits = 0x00; break; default: snd_printk("MPU-401 port 0x%lx not valid\n", chip->mpu_port); goto __skip_mpu; } switch (chip->mpu_irq) { case 5: mpu_irq_bits = 0x02; break; case 7: mpu_irq_bits = 0x03; break; case 9: mpu_irq_bits = 0x00; break; case 10: mpu_irq_bits = 0x01; break; default: snd_printk("MPU-401 irq # %d not valid\n", chip->mpu_irq); goto __skip_mpu; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), (chip->mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); }__skip_mpu: return 0;}#ifdef OPTi93Xstatic unsigned char snd_opti93x_default_image[32] ={ 0x00, /* 00/00 - l_mixout_outctrl */ 0x00, /* 01/01 - r_mixout_outctrl */ 0x88, /* 02/02 - l_cd_inctrl */ 0x88, /* 03/03 - r_cd_inctrl */ 0x88, /* 04/04 - l_a1/fm_inctrl */ 0x88, /* 05/05 - r_a1/fm_inctrl */ 0x80, /* 06/06 - l_dac_inctrl */ 0x80, /* 07/07 - r_dac_inctrl */ 0x00, /* 08/08 - ply_dataform_reg */ 0x00, /* 09/09 - if_conf */ 0x00, /* 0a/10 - pin_ctrl */ 0x00, /* 0b/11 - err_init_reg */ 0x0a, /* 0c/12 - id_reg */ 0x00, /* 0d/13 - reserved */ 0x00, /* 0e/14 - ply_upcount_reg */ 0x00, /* 0f/15 - ply_lowcount_reg */ 0x88, /* 10/16 - reserved/l_a1_inctrl */ 0x88, /* 11/17 - reserved/r_a1_inctrl */ 0x88, /* 12/18 - l_line_inctrl */ 0x88, /* 13/19 - r_line_inctrl */ 0x88, /* 14/20 - l_mic_inctrl */ 0x88, /* 15/21 - r_mic_inctrl */ 0x80, /* 16/22 - l_out_outctrl */ 0x80, /* 17/23 - r_out_outctrl */ 0x00, /* 18/24 - reserved */ 0x00, /* 19/25 - reserved */ 0x00, /* 1a/26 - reserved */ 0x00, /* 1b/27 - reserved */ 0x00, /* 1c/28 - cap_dataform_reg */ 0x00, /* 1d/29 - reserved */ 0x00, /* 1e/30 - cap_upcount_reg */ 0x00 /* 1f/31 - cap_lowcount_reg */};static int snd_opti93x_busy_wait(struct snd_opti93x *chip){ int timeout; for (timeout = 250; timeout-- > 0; udelay(10)) if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT)) return 0; snd_printk("chip still busy.\n"); return -EBUSY;}static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg){ snd_opti93x_busy_wait(chip); outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); return inb(OPTi93X_PORT(chip, DATA));}static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg, unsigned char value){ snd_opti93x_busy_wait(chip); outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); outb(value, OPTi93X_PORT(chip, DATA));}static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg, unsigned char value){ snd_opti93x_out(chip, reg, chip->image[reg] = value);}static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg, unsigned char mask, unsigned char value){ snd_opti93x_out_image(chip, reg, (chip->image[reg] & ~mask) | (value & mask));}static void snd_opti93x_mce_up(struct snd_opti93x *chip){ snd_opti93x_busy_wait(chip); chip->mce_bit = OPTi93X_MCE; if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)) outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));}static void snd_opti93x_mce_down(struct snd_opti93x *chip){ snd_opti93x_busy_wait(chip); chip->mce_bit = 0; if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE) outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));}#define snd_opti93x_mute_reg(chip, reg, mute) \ snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]);static void snd_opti93x_mute(struct snd_opti93x *chip, int mute){ mute = mute ? 1 : 0; if (chip->mute == mute) return; chip->mute = mute; snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute); switch (chip->hardware) { case OPTi9XX_HW_82C930: snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute); break; case OPTi9XX_HW_82C931: case OPTi9XX_HW_82C933: snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute); } snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute); snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute); snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute);}static unsigned int snd_opti93x_get_count(unsigned char format, unsigned int size){ switch (format & 0xe0) { case OPTi93X_LINEAR_16_LIT: case OPTi93X_LINEAR_16_BIG: size >>= 1; break; case OPTi93X_ADPCM_16: return size >> 2; } return (format & OPTi93X_STEREO) ? (size >> 1) : size;}static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, 18900, 22050, 27428, 32000, 33075, 37800, 44100, 48000 };#define RATES ARRAY_SIZE(rates)static struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = RATES, .list = rates, .mask = 0,};static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09, 0x0b, 0x0c};static unsigned char snd_opti93x_get_freq(unsigned int rate){ unsigned int i; for (i = 0; i < RATES; i++) { if (rate == rates[i]) return bits[i]; } snd_BUG(); return bits[RATES-1];}static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip, unsigned int format, int channels){ unsigned char retval = OPTi93X_LINEAR_8; switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: retval = OPTi93X_ULAW_8; break; case SNDRV_PCM_FORMAT_A_LAW: retval = OPTi93X_ALAW_8; break; case SNDRV_PCM_FORMAT_S16_LE: retval = OPTi93X_LINEAR_16_LIT; break; case SNDRV_PCM_FORMAT_S16_BE: retval = OPTi93X_LINEAR_16_BIG; break; case SNDRV_PCM_FORMAT_IMA_ADPCM: retval = OPTi93X_ADPCM_16; } return (channels > 1) ? (retval | OPTi93X_STEREO) : retval;}static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt){ unsigned char mask; snd_opti93x_mute(chip, 1); snd_opti93x_mce_up(chip); mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff; snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt); snd_opti93x_mce_down(chip); snd_opti93x_mute(chip, 0);}static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt){ snd_opti93x_mute(chip, 1); snd_opti93x_mce_up(chip); if (!(chip->mode & OPTi93X_MODE_PLAY)) snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt); else fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0; snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt); snd_opti93x_mce_down(chip); snd_opti93x_mute(chip, 0);}static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode){ unsigned long flags; spin_lock_irqsave(&chip->lock, flags); if (chip->mode & mode) { spin_unlock_irqrestore(&chip->lock, flags); return -EAGAIN; } if (!(chip->mode & OPTi93X_MODE_OPEN)) { outb(0x00, OPTi93X_PORT(chip, STATUS)); snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); chip->mode = mode; } else chip->mode |= mode; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode){ unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->mode &= ~mode; if (chip->mode & OPTi93X_MODE_OPEN) { spin_unlock_irqrestore(&chip->lock, flags); return; } snd_opti93x_mute(chip, 1); outb(0, OPTi93X_PORT(chip, STATUS)); snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, ~OPTi93X_IRQ_ENABLE); snd_opti93x_mce_up(chip); snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); snd_opti93x_mce_down(chip); chip->mode = 0; snd_opti93x_mute(chip, 0); spin_unlock_irqrestore(&chip->lock, flags);}static int snd_opti93x_trigger(struct snd_pcm_substream *substream, unsigned char what, int cmd){ struct snd_opti93x *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; struct list_head *pos; struct snd_pcm_substream *s; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= OPTi93X_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); } else if (s == chip->capture_substream) { what |= OPTi93X_CAPTURE_ENABLE; snd_pcm_trigger_done(s, substream); } } spin_lock(&chip->lock); if (cmd == SNDRV_PCM_TRIGGER_START) { snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); if (what & OPTi93X_CAPTURE_ENABLE) udelay(50); } else snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); spin_unlock(&chip->lock); break; } default: return -EINVAL; } return 0;}static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd){ return snd_opti93x_trigger(substream, OPTi93X_PLAYBACK_ENABLE, cmd);}static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd){ return snd_opti93x_trigger(substream, OPTi93X_CAPTURE_ENABLE, cmd);}static int snd_opti93x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_opti93x_hw_free(struct snd_pcm_substream *substream){ snd_pcm_lib_free_pages(substream); return 0;}static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream){ struct snd_opti93x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned long flags; unsigned char format; unsigned int count = snd_pcm_lib_period_bytes(substream); unsigned int size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->lock, flags); chip->p_dma_size = size; snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); format = snd_opti93x_get_freq(runtime->rate); format |= snd_opti93x_get_format(chip, runtime->format, runtime->channels); snd_opti93x_playback_format(chip, format); format = chip->image[OPTi93X_PLAY_FORMAT]; count = snd_opti93x_get_count(format, count) - 1; snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream){ struct snd_opti93x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned long flags; unsigned char format; unsigned int count = snd_pcm_lib_period_bytes(substream); unsigned int size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->lock, flags); chip->c_dma_size = size; snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); format = snd_opti93x_get_freq(runtime->rate); format |= snd_opti93x_get_format(chip, runtime->format, runtime->channels); snd_opti93x_capture_format(chip, format); format = chip->image[OPTi93X_CAPT_FORMAT]; count = snd_opti93x_get_count(format, count) - 1; snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); spin_unlock_irqrestore(&chip->lock, flags); return 0;}static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream){ struct snd_opti93x *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) return 0; ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); return bytes_to_frames(substream->runtime, ptr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -