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

📄 via82xx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -