📄 via82xx.c
字号:
idx = count >> 24; if (idx >= viadev->tbl_entries) {#ifdef POINTER_DEBUG printk(KERN_DEBUG "fail: invalid idx = %i/%i\n", idx, viadev->tbl_entries);#endif res = viadev->lastpos; } else { count &= 0xffffff; res = calc_linear_pos(viadev, idx, count); } } else { res = viadev->hwptr_done; if (!viadev->in_interrupt) { if (status & VIA_REG_STAT_EOL) { res = 0; } else if (status & VIA_REG_STAT_FLAG) { res += viadev->fragsize; } } } unlock: viadev->lastpos = res; spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res);}/* * hw_params callback: * allocate the buffer and build up the buffer description table */static int snd_via82xx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; err = build_via_table(viadev, substream, chip->pci, params_periods(hw_params), params_period_bytes(hw_params)); if (err < 0) return err; return 0;}/* * hw_free callback: * clean up the buffer description table and release the buffer */static int snd_via82xx_hw_free(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; clean_via_table(viadev, substream, chip->pci); snd_pcm_lib_free_pages(substream); return 0;}/* * set up the table pointer */static void snd_via82xx_set_table_ptr(struct via82xx *chip, struct viadev *viadev){ snd_via82xx_codec_ready(chip, 0); outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR)); udelay(20); snd_via82xx_codec_ready(chip, 0);}/* * prepare callback for playback and capture on via686 */static void via686_setup_format(struct via82xx *chip, struct viadev *viadev, struct snd_pcm_runtime *runtime){ snd_via82xx_channel_reset(chip, viadev); /* this must be set after channel_reset */ snd_via82xx_set_table_ptr(chip, viadev); outb(VIA_REG_TYPE_AUTOSTART | (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) | (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) | ((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) | VIA_REG_TYPE_INT_EOL | VIA_REG_TYPE_INT_FLAG, VIADEV_REG(viadev, OFFSET_TYPE));}static int snd_via686_playback_prepare(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); via686_setup_format(chip, viadev, runtime); return 0;}static int snd_via686_capture_prepare(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); via686_setup_format(chip, viadev, runtime); return 0;}/* * lock the current rate */static int via_lock_rate(struct via_rate_lock *rec, int rate){ int changed = 0; spin_lock_irq(&rec->lock); if (rec->rate != rate) { if (rec->rate && rec->used > 1) /* already set */ changed = -EINVAL; else { rec->rate = rate; changed = 1; } } spin_unlock_irq(&rec->lock); return changed;}/* * prepare callback for DSX playback on via823x */static int snd_via8233_playback_prepare(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int ac97_rate = chip->dxs_src ? 48000 : runtime->rate; int rate_changed; u32 rbits; if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0) return rate_changed; if (rate_changed) snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, chip->no_vra ? 48000 : runtime->rate); if (chip->spdif_on && viadev->reg_offset == 0x30) snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); if (runtime->rate == 48000) rbits = 0xfffff; else rbits = (0x100000 / 48000) * runtime->rate + ((0x100000 % 48000) * runtime->rate) / 48000; snd_assert((rbits & ~0xfffff) == 0, return -EINVAL); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); outb(chip->playback_volume[viadev->reg_offset / 0x10][0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L)); outb(chip->playback_volume[viadev->reg_offset / 0x10][1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */ (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | /* stereo */ rbits | /* rate */ 0xff000000, /* STOP index is never reached */ VIADEV_REG(viadev, OFFSET_STOP_IDX)); udelay(20); snd_via82xx_codec_ready(chip, 0); return 0;}/* * prepare callback for multi-channel playback on via823x */static int snd_via8233_multi_prepare(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int slots; int fmt; if (via_lock_rate(&chip->rates[0], runtime->rate) < 0) return -EINVAL; snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT; fmt |= runtime->channels << 4; outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));#if 0 if (chip->revision == VIA_REV_8233A) slots = 0; else#endif { /* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */ /* corresponding to FL, FR, RL, RR, C, LFE ?? */ switch (runtime->channels) { case 1: slots = (1<<0) | (1<<4); break; case 2: slots = (1<<0) | (2<<4); break; case 3: slots = (1<<0) | (2<<4) | (5<<8); break; case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break; case 5: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16); break; case 6: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16) | (6<<20); break; default: slots = 0; break; } } /* STOP index is never reached */ outl(0xff000000 | slots, VIADEV_REG(viadev, OFFSET_STOP_IDX)); udelay(20); snd_via82xx_codec_ready(chip, 0); return 0;}/* * prepare callback for capture on via823x */static int snd_via8233_capture_prepare(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; if (via_lock_rate(&chip->rates[1], runtime->rate) < 0) return -EINVAL; snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIADEV_REG(viadev, OFS_CAPTURE_FIFO)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | 0xff000000, /* STOP index is never reached */ VIADEV_REG(viadev, OFFSET_STOP_IDX)); udelay(20); snd_via82xx_codec_ready(chip, 0); return 0;}/* * pcm hardware definition, identical for both playback and capture */static struct snd_pcm_hardware snd_via82xx_hw ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | /* SNDRV_PCM_INFO_RESUME | */ SNDRV_PCM_INFO_PAUSE), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 32, .period_bytes_max = 128 * 1024, .periods_min = 2, .periods_max = VIA_TABLE_SIZE / 2, .fifo_size = 0,};/* * open callback skeleton */static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev, struct snd_pcm_substream *substream){ struct snd_pcm_runtime *runtime = substream->runtime; int err; struct via_rate_lock *ratep; runtime->hw = snd_via82xx_hw; /* set the hw rate condition */ ratep = &chip->rates[viadev->direction]; spin_lock_irq(&ratep->lock); ratep->used++; if (chip->spdif_on && viadev->reg_offset == 0x30) { /* DXS#3 and spdif is on */ runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF]; snd_pcm_limit_hw_rates(runtime); } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) { /* fixed DXS playback rate */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; } else if (chip->dxs_src && viadev->reg_offset < 0x40) { /* use full SRC capabilities of DXS */ runtime->hw.rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000); runtime->hw.rate_min = 8000; runtime->hw.rate_max = 48000; } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; snd_pcm_limit_hw_rates(runtime); } else { /* a fixed rate */ runtime->hw.rates = SNDRV_PCM_RATE_KNOT; runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate; } spin_unlock_irq(&ratep->lock); /* we may remove following constaint when we modify table entries in interrupt */ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; runtime->private_data = viadev; viadev->substream = substream; return 0;}/* * open callback for playback on via686 and via823x DSX */static int snd_via82xx_playback_open(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = &chip->devs[chip->playback_devno + substream->number]; int err; if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) return err; return 0;}/* * open callback for playback on via823x multi-channel */static int snd_via8233_multi_open(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = &chip->devs[chip->multi_devno]; int err; /* channels constraint for VIA8233A * 3 and 5 channels are not supported */ static unsigned int channels[] = { 1, 2, 4, 6 }; static struct snd_pcm_hw_constraint_list hw_constraints_channels = { .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, }; if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) return err; substream->runtime->hw.channels_max = 6; if (chip->revision == VIA_REV_8233A) snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); return 0;}/* * open callback for capture on via686 and via823x */static int snd_via82xx_capture_open(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = &chip->devs[chip->capture_devno + substream->pcm->device]; return snd_via82xx_pcm_open(chip, viadev, substream);}/* * close callback */static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream){ struct via82xx *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; struct via_rate_lock *ratep; /* release the rate lock */ ratep = &chip->rates[viadev->direction]; spin_lock_irq(&ratep->lock); ratep->used--; if (! ratep->used) ratep->rate = 0; spin_unlock_irq(&ratep->lock); if (! ratep->rate) { if (! viadev->direction) { snd_ac97_update_power(chip->ac97, AC97_PCM_FRONT_DAC_RATE, 0); snd_ac97_update_power(chip->ac97, AC97_PCM_SURR_DAC_RATE, 0); snd_ac97_update_power(chip->ac97, AC97_PCM_LFE_DAC_RATE, 0); } else snd_ac97_update_power(chip->ac97, AC97_PCM_LR_ADC_RATE, 0); } viadev->substream = NULL; return 0;}/* via686 playback callbacks */static struct snd_pcm_ops snd_via686_playback_ops = { .open = snd_via82xx_playback_open, .close = snd_via82xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_via82xx_hw_params, .hw_free = snd_via82xx_hw_free, .prepare = snd_via686_playback_prepare, .trigger = snd_via82xx_pcm_trigger, .pointer = snd_via686_pcm_pointer, .page = snd_pcm_sgbuf_ops_page,};/* via686 capture callbacks */static struct snd_pcm_ops snd_via686_capture_ops = { .open = snd_via82xx_capture_open, .close = snd_via82xx_pcm_close,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -