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

📄 cmipci.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	if ((err = open_device_check(cm, CM_OPEN_SPDIF_PLAYBACK, substream)) < 0) /* use channel A */		return err;	if (cm->can_ac3_hw) {		runtime->hw = snd_cmipci_playback_spdif;		if (cm->chip_version >= 37) {			runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE;			snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);		}		if (cm->chip_version == 68) {			runtime->hw.rates |= SNDRV_PCM_RATE_88200 |					     SNDRV_PCM_RATE_96000;			runtime->hw.rate_max = 96000;		}	} else {		runtime->hw = snd_cmipci_playback_iec958_subframe;	}	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000);	cm->dig_pcm_status = cm->dig_status;	return 0;}static int snd_cmipci_capture_spdif_open(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */		return err;	runtime->hw = snd_cmipci_capture_spdif;	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000);	return 0;}/* */static int snd_cmipci_playback_close(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	close_device_check(cm, CM_OPEN_PLAYBACK);	return 0;}static int snd_cmipci_capture_close(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	close_device_check(cm, CM_OPEN_CAPTURE);	return 0;}static int snd_cmipci_playback2_close(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	close_device_check(cm, CM_OPEN_PLAYBACK2);	close_device_check(cm, CM_OPEN_PLAYBACK_MULTI);	return 0;}static int snd_cmipci_playback_spdif_close(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	close_device_check(cm, CM_OPEN_SPDIF_PLAYBACK);	return 0;}static int snd_cmipci_capture_spdif_close(struct snd_pcm_substream *substream){	struct cmipci *cm = snd_pcm_substream_chip(substream);	close_device_check(cm, CM_OPEN_SPDIF_CAPTURE);	return 0;}/* */static struct snd_pcm_ops snd_cmipci_playback_ops = {	.open =		snd_cmipci_playback_open,	.close =	snd_cmipci_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_cmipci_hw_params,	.hw_free =	snd_cmipci_playback_hw_free,	.prepare =	snd_cmipci_playback_prepare,	.trigger =	snd_cmipci_playback_trigger,	.pointer =	snd_cmipci_playback_pointer,};static struct snd_pcm_ops snd_cmipci_capture_ops = {	.open =		snd_cmipci_capture_open,	.close =	snd_cmipci_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_cmipci_hw_params,	.hw_free =	snd_cmipci_hw_free,	.prepare =	snd_cmipci_capture_prepare,	.trigger =	snd_cmipci_capture_trigger,	.pointer =	snd_cmipci_capture_pointer,};static struct snd_pcm_ops snd_cmipci_playback2_ops = {	.open =		snd_cmipci_playback2_open,	.close =	snd_cmipci_playback2_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_cmipci_playback2_hw_params,	.hw_free =	snd_cmipci_playback2_hw_free,	.prepare =	snd_cmipci_capture_prepare,	/* channel B */	.trigger =	snd_cmipci_capture_trigger,	/* channel B */	.pointer =	snd_cmipci_capture_pointer,	/* channel B */};static struct snd_pcm_ops snd_cmipci_playback_spdif_ops = {	.open =		snd_cmipci_playback_spdif_open,	.close =	snd_cmipci_playback_spdif_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_cmipci_hw_params,	.hw_free =	snd_cmipci_playback_hw_free,	.prepare =	snd_cmipci_playback_spdif_prepare,	/* set up rate */	.trigger =	snd_cmipci_playback_trigger,	.pointer =	snd_cmipci_playback_pointer,};static struct snd_pcm_ops snd_cmipci_capture_spdif_ops = {	.open =		snd_cmipci_capture_spdif_open,	.close =	snd_cmipci_capture_spdif_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_cmipci_hw_params,	.hw_free =	snd_cmipci_capture_spdif_hw_free,	.prepare =	snd_cmipci_capture_spdif_prepare,	.trigger =	snd_cmipci_capture_trigger,	.pointer =	snd_cmipci_capture_pointer,};/* */static int __devinit snd_cmipci_pcm_new(struct cmipci *cm, int device){	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_ops);	pcm->private_data = cm;	pcm->info_flags = 0;	strcpy(pcm->name, "C-Media PCI DAC/ADC");	cm->pcm = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);	return 0;}static int __devinit snd_cmipci_pcm2_new(struct cmipci *cm, int device){	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 0, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback2_ops);	pcm->private_data = cm;	pcm->info_flags = 0;	strcpy(pcm->name, "C-Media PCI 2nd DAC");	cm->pcm2 = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);	return 0;}static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device){	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_spdif_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_spdif_ops);	pcm->private_data = cm;	pcm->info_flags = 0;	strcpy(pcm->name, "C-Media PCI IEC958");	cm->pcm_spdif = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024);	return 0;}/* * mixer interface: * - CM8338/8738 has a compatible mixer interface with SB16, but *   lack of some elements like tone control, i/o gain and AGC. * - Access to native registers: *   - A 3D switch *   - Output mute switches */static void snd_cmipci_mixer_write(struct cmipci *s, unsigned char idx, unsigned char data){	outb(idx, s->iobase + CM_REG_SB16_ADDR);	outb(data, s->iobase + CM_REG_SB16_DATA);}static unsigned char snd_cmipci_mixer_read(struct cmipci *s, unsigned char idx){	unsigned char v;	outb(idx, s->iobase + CM_REG_SB16_ADDR);	v = inb(s->iobase + CM_REG_SB16_DATA);	return v;}/* * general mixer element */struct cmipci_sb_reg {	unsigned int left_reg, right_reg;	unsigned int left_shift, right_shift;	unsigned int mask;	unsigned int invert: 1;	unsigned int stereo: 1;};#define COMPOSE_SB_REG(lreg,rreg,lshift,rshift,mask,invert,stereo) \ ((lreg) | ((rreg) << 8) | (lshift << 16) | (rshift << 19) | (mask << 24) | (invert << 22) | (stereo << 23))#define CMIPCI_DOUBLE(xname, left_reg, right_reg, left_shift, right_shift, mask, invert, stereo) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_volume, \  .get = snd_cmipci_get_volume, .put = snd_cmipci_put_volume, \  .private_value = COMPOSE_SB_REG(left_reg, right_reg, left_shift, right_shift, mask, invert, stereo), \}#define CMIPCI_SB_VOL_STEREO(xname,reg,shift,mask) CMIPCI_DOUBLE(xname, reg, reg+1, shift, shift, mask, 0, 1)#define CMIPCI_SB_VOL_MONO(xname,reg,shift,mask) CMIPCI_DOUBLE(xname, reg, reg, shift, shift, mask, 0, 0)#define CMIPCI_SB_SW_STEREO(xname,lshift,rshift) CMIPCI_DOUBLE(xname, SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, lshift, rshift, 1, 0, 1)#define CMIPCI_SB_SW_MONO(xname,shift) CMIPCI_DOUBLE(xname, SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, shift, shift, 1, 0, 0)static void cmipci_sb_reg_decode(struct cmipci_sb_reg *r, unsigned long val){	r->left_reg = val & 0xff;	r->right_reg = (val >> 8) & 0xff;	r->left_shift = (val >> 16) & 0x07;	r->right_shift = (val >> 19) & 0x07;	r->invert = (val >> 22) & 1;	r->stereo = (val >> 23) & 1;	r->mask = (val >> 24) & 0xff;}static int snd_cmipci_info_volume(struct snd_kcontrol *kcontrol,				  struct snd_ctl_elem_info *uinfo){	struct cmipci_sb_reg reg;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = reg.stereo + 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = reg.mask;	return 0;} static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct cmipci *cm = snd_kcontrol_chip(kcontrol);	struct cmipci_sb_reg reg;	int val;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	val = (snd_cmipci_mixer_read(cm, reg.left_reg) >> reg.left_shift) & reg.mask;	if (reg.invert)		val = reg.mask - val;	ucontrol->value.integer.value[0] = val;	if (reg.stereo) {		val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask;		if (reg.invert)			val = reg.mask - val;		 ucontrol->value.integer.value[1] = val;	}	spin_unlock_irq(&cm->reg_lock);	return 0;}static int snd_cmipci_put_volume(struct snd_kcontrol *kcontrol,				 struct snd_ctl_elem_value *ucontrol){	struct cmipci *cm = snd_kcontrol_chip(kcontrol);	struct cmipci_sb_reg reg;	int change;	int left, right, oleft, oright;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	left = ucontrol->value.integer.value[0] & reg.mask;	if (reg.invert)		left = reg.mask - left;	left <<= reg.left_shift;	if (reg.stereo) {		right = ucontrol->value.integer.value[1] & reg.mask;		if (reg.invert)			right = reg.mask - right;		right <<= reg.right_shift;	} else		right = 0;	spin_lock_irq(&cm->reg_lock);	oleft = snd_cmipci_mixer_read(cm, reg.left_reg);	left |= oleft & ~(reg.mask << reg.left_shift);	change = left != oleft;	if (reg.stereo) {		if (reg.left_reg != reg.right_reg) {			snd_cmipci_mixer_write(cm, reg.left_reg, left);			oright = snd_cmipci_mixer_read(cm, reg.right_reg);		} else			oright = left;		right |= oright & ~(reg.mask << reg.right_shift);		change |= right != oright;		snd_cmipci_mixer_write(cm, reg.right_reg, right);	} else		snd_cmipci_mixer_write(cm, reg.left_reg, left);	spin_unlock_irq(&cm->reg_lock);	return change;}/* * input route (left,right) -> (left,right) */#define CMIPCI_SB_INPUT_SW(xname, left_shift, right_shift) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_input_sw, \  .get = snd_cmipci_get_input_sw, .put = snd_cmipci_put_input_sw, \  .private_value = COMPOSE_SB_REG(SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, left_shift, right_shift, 1, 0, 1), \}static int snd_cmipci_info_input_sw(struct snd_kcontrol *kcontrol,				    struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 4;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;} static int snd_cmipci_get_input_sw(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct cmipci *cm = snd_kcontrol_chip(kcontrol);	struct cmipci_sb_reg reg;	int val1, val2;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	val1 = snd_cmipci_mixer_read(cm, reg.left_reg);	val2 = snd_cmipci_mixer_read(cm, reg.right_reg);	spin_unlock_irq(&cm->reg_lock);	ucontrol->value.integer.value[0] = (val1 >> reg.left_shift) & 1;	ucontrol->value.integer.value[1] = (val2 >> reg.left_shift) & 1;	ucontrol->value.integer.value[2] = (val1 >> reg.right_shift) & 1;	ucontrol->value.integer.value[3] = (val2 >> reg.right_shift) & 1;	return 0;}static int snd_cmipci_put_input_sw(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct cmipci *cm = snd_kcontrol_chip(kcontrol);	struct cmipci_sb_reg reg;	int change;	int val1, val2, oval1, oval2;	cmipci_sb_reg_decode(&reg, kcontrol->private_value);	spin_lock_irq(&cm->reg_lock);	oval1 = snd_cmipci_mixer_read(cm, reg.left_reg);	oval2 = snd_cmipci_mixer_read(cm, reg.right_reg);	val1 = oval1 & ~((1 << reg.left_shift) | (1 << reg.right_shift));	val2 = oval2 & ~((1 << reg.left_shift) | (1 << reg.right_shift));	val1 |= (ucontrol->value.integer.value[0] & 1) << reg.left_shift;	val2 |= (ucontrol->value.integer.value[1] & 1) << reg.left_shift;	val1 |= (ucontrol->value.integer.value[2] & 1) << reg.right_shift;	val2 |= (ucontrol->value.integer.value[3] & 1) << reg.right_shift;	change = val1 != oval1 || val2 != oval2;	snd_cmipci_mixer_write(cm, reg.left_reg, val1);	snd_cmipci_mixer_write(cm, reg.right_reg, val2);	spin_unlock_irq(&cm->reg_lock);	return change;}/* * native mixer switches/volumes */#define CMIPCI_MIXER_SW_STEREO(xname, reg, lshift, rshift, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_cmipci_info_native_mixer, \  .get = snd_cmipci_get_native_mixer, .put = snd_cmipci_put_native_mixer, \  .private_value = COMPOSE_SB_REG(reg, reg, lshift, rshift, 1, invert, 1), \}#define CMIPCI_MIXER_SW_MONO(xname, reg, shift, inve

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -