📄 intel8x0.c
字号:
int dbl = params_rate(hw_params) > 48000; int err; if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ ichdev->page_attr_changed = 0; } err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; if (chip->fix_nocache) { if (runtime->dma_area && ! ichdev->page_attr_changed) { fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); ichdev->page_attr_changed = 1; } } if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), params_channels(hw_params), ichdev->pcm->r[dbl].slots); if (err >= 0) { ichdev->pcm_open_flag = 1; /* Force SPDIF setting */ if (ichdev->ichd == ICHD_PCMOUT && chip->spdif_idx < 0) snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, params_rate(hw_params)); } return err;}static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); ichdev->page_attr_changed = 0; } return snd_pcm_lib_free_pages(substream);}static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, struct snd_pcm_runtime *runtime){ unsigned int cnt; int dbl = runtime->rate > 48000; spin_lock_irq(&chip->reg_lock); switch (chip->device_type) { case DEVICE_ALI: cnt = igetdword(chip, ICHREG(ALI_SCR)); cnt &= ~ICH_ALI_SC_PCM_246_MASK; if (runtime->channels == 4 || dbl) cnt |= ICH_ALI_SC_PCM_4; else if (runtime->channels == 6) cnt |= ICH_ALI_SC_PCM_6; iputdword(chip, ICHREG(ALI_SCR), cnt); break; case DEVICE_SIS: cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~ICH_SIS_PCM_246_MASK; if (runtime->channels == 4 || dbl) cnt |= ICH_SIS_PCM_4; else if (runtime->channels == 6) cnt |= ICH_SIS_PCM_6; iputdword(chip, ICHREG(GLOB_CNT), cnt); break; default: cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~(ICH_PCM_246_MASK | ICH_PCM_20BIT); if (runtime->channels == 4 || dbl) cnt |= ICH_PCM_4; else if (runtime->channels == 6) cnt |= ICH_PCM_6; if (chip->device_type == DEVICE_NFORCE) { /* reset to 2ch once to keep the 6 channel data in alignment, * to start from Front Left always */ if (cnt & ICH_PCM_246_MASK) { iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_PCM_246_MASK); spin_unlock_irq(&chip->reg_lock); msleep(50); /* grrr... */ spin_lock_irq(&chip->reg_lock); } } else if (chip->device_type == DEVICE_INTEL_ICH4) { if (runtime->sample_bits > 16) cnt |= ICH_PCM_20BIT; } iputdword(chip, ICHREG(GLOB_CNT), cnt); break; } spin_unlock_irq(&chip->reg_lock);}static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct ichdev *ichdev = get_ichdev(substream); ichdev->physbuf = runtime->dma_addr; ichdev->size = snd_pcm_lib_buffer_bytes(substream); ichdev->fragsize = snd_pcm_lib_period_bytes(substream); if (ichdev->ichd == ICHD_PCMOUT) { snd_intel8x0_setup_pcm_out(chip, runtime); if (chip->device_type == DEVICE_INTEL_ICH4) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); return 0;}static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); size_t ptr1, ptr; int civ, timeout = 100; unsigned int position; spin_lock(&chip->reg_lock); do { civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); position = ichdev->position; if (ptr1 == 0) { udelay(10); continue; } if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; return bytes_to_frames(substream->runtime, ptr);}static struct snd_pcm_hardware snd_intel8x0_stream ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 128 * 1024, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static unsigned int channels4[] = { 2, 4,};static struct snd_pcm_hw_constraint_list hw_constraints_channels4 = { .count = ARRAY_SIZE(channels4), .list = channels4, .mask = 0,};static unsigned int channels6[] = { 2, 4, 6,};static struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { .count = ARRAY_SIZE(channels6), .list = channels6, .mask = 0,};static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; ichdev->substream = substream; runtime->hw = snd_intel8x0_stream; runtime->hw.rates = ichdev->pcm->rates; snd_pcm_limit_hw_rates(runtime); if (chip->device_type == DEVICE_SIS) { runtime->hw.buffer_bytes_max = 64*1024; runtime->hw.period_bytes_max = 64*1024; } if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; runtime->private_data = ichdev; return 0;}static int snd_intel8x0_playback_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; err = snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMOUT]); if (err < 0) return err; if (chip->multi6) { runtime->hw.channels_max = 6; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels6); } else if (chip->multi4) { runtime->hw.channels_max = 4; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels4); } if (chip->dra) { snd_ac97_pcm_double_rate_rules(runtime); } if (chip->smp20bit) { runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; snd_pcm_hw_constraint_msbits(runtime, 0, 32, 20); } return 0;}static int snd_intel8x0_playback_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCMOUT].substream = NULL; return 0;}static int snd_intel8x0_capture_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMIN]);}static int snd_intel8x0_capture_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCMIN].substream = NULL; return 0;}static int snd_intel8x0_mic_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC]);}static int snd_intel8x0_mic_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MIC].substream = NULL; return 0;}static int snd_intel8x0_mic2_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC2]);}static int snd_intel8x0_mic2_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MIC2].substream = NULL; return 0;}static int snd_intel8x0_capture2_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCM2IN]);}static int snd_intel8x0_capture2_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCM2IN].substream = NULL; return 0;}static int snd_intel8x0_spdif_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; return snd_intel8x0_pcm_open(substream, &chip->ichd[idx]);}static int snd_intel8x0_spdif_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; chip->ichd[idx].substream = NULL; return 0;}static int snd_intel8x0_ali_ac97spdifout_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); unsigned int val; spin_lock_irq(&chip->reg_lock); val = igetdword(chip, ICHREG(ALI_INTERFACECR)); val |= ICH_ALI_IF_AC97SP; iputdword(chip, ICHREG(ALI_INTERFACECR), val); /* also needs to set ALI_SC_CODEC_SPDF correctly */ spin_unlock_irq(&chip->reg_lock); return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]);}static int snd_intel8x0_ali_ac97spdifout_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); unsigned int val; chip->ichd[ALID_AC97SPDIFOUT].substream = NULL; spin_lock_irq(&chip->reg_lock); val = igetdword(chip, ICHREG(ALI_INTERFACECR)); val &= ~ICH_ALI_IF_AC97SP; iputdword(chip, ICHREG(ALI_INTERFACECR), val); spin_unlock_irq(&chip->reg_lock); return 0;}#if 0 // NYIstatic int snd_intel8x0_ali_spdifin_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFIN]);}static int snd_intel8x0_ali_spdifin_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ALID_SPDIFIN].substream = NULL; return 0;}static int snd_intel8x0_ali_spdifout_open(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFOUT]);}static int snd_intel8x0_ali_spdifout_close(struct snd_pcm_substream *substream){ struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ALID_SPDIFOUT].substream = NULL; return 0;}#endifstatic struct snd_pcm_ops snd_intel8x0_playback_ops = { .open = snd_intel8x0_playback_open, .close = snd_intel8x0_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_capture_ops = { .open = snd_intel8x0_capture_open, .close = snd_intel8x0_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_capture_mic_ops = { .open = snd_intel8x0_mic_open, .close = snd_intel8x0_mic_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_capture_mic2_ops = { .open = snd_intel8x0_mic2_open, .close = snd_intel8x0_mic2_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_capture2_ops = { .open = snd_intel8x0_capture2_open, .close = snd_intel8x0_capture2_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_spdif_ops = { .open = snd_intel8x0_spdif_open, .close = snd_intel8x0_spdif_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0_ali_playback_ops = { .open = snd_intel8x0_playback_open, .close = snd_intel8x0_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -