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

📄 opti92x-ad1848.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 4 页
字号:
	ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);	return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_opti93x_capture_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_CAPTURE_ENABLE))		return 0;	ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);	return bytes_to_frames(substream->runtime, ptr);}static void snd_opti93x_overrange(struct snd_opti93x *chip){	unsigned long flags;	spin_lock_irqsave(&chip->lock, flags);	if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02))		chip->capture_substream->runtime->overrange++;	spin_unlock_irqrestore(&chip->lock, flags);}static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct snd_opti93x *codec = dev_id;	unsigned char status;	status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11));	if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)		snd_pcm_period_elapsed(codec->playback_substream);	if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {		snd_opti93x_overrange(codec);		snd_pcm_period_elapsed(codec->capture_substream);	}	outb(0x00, OPTi93X_PORT(codec, STATUS));	return IRQ_HANDLED;}static struct snd_pcm_hardware snd_opti93x_playback = {	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5512,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static struct snd_pcm_hardware snd_opti93x_capture = {	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),	.rates =		SNDRV_PCM_RATE_8000_48000,	.rate_min =		5512,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static int snd_opti93x_playback_open(struct snd_pcm_substream *substream){	int error;	struct snd_opti93x *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0)		return error;	snd_pcm_set_sync(substream);	chip->playback_substream = substream;	runtime->hw = snd_opti93x_playback;	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);	return error;}static int snd_opti93x_capture_open(struct snd_pcm_substream *substream){	int error;	struct snd_opti93x *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0)		return error;	runtime->hw = snd_opti93x_capture;	snd_pcm_set_sync(substream);	chip->capture_substream = substream;	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);	return error;}static int snd_opti93x_playback_close(struct snd_pcm_substream *substream){	struct snd_opti93x *chip = snd_pcm_substream_chip(substream);	chip->playback_substream = NULL;	snd_opti93x_close(chip, OPTi93X_MODE_PLAY);	return 0;}static int snd_opti93x_capture_close(struct snd_pcm_substream *substream){	struct snd_opti93x *chip = snd_pcm_substream_chip(substream);	chip->capture_substream = NULL;	snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE);	return 0;}static void snd_opti93x_init(struct snd_opti93x *chip){	unsigned long flags;	int i;	spin_lock_irqsave(&chip->lock, flags);	snd_opti93x_mce_up(chip);	for (i = 0; i < 32; i++)		snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]);	snd_opti93x_mce_down(chip);	spin_unlock_irqrestore(&chip->lock, flags);}static int snd_opti93x_probe(struct snd_opti93x *chip){	unsigned long flags;	unsigned char val;	spin_lock_irqsave(&chip->lock, flags);	val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f;	spin_unlock_irqrestore(&chip->lock, flags);	return (val == 0x0a) ? 0 : -ENODEV;}static int snd_opti93x_free(struct snd_opti93x *chip){	release_and_free_resource(chip->res_port);	if (chip->dma1 >= 0) {		disable_dma(chip->dma1);		free_dma(chip->dma1);	}	if (chip->dma2 >= 0) {		disable_dma(chip->dma2);		free_dma(chip->dma2);	}	if (chip->irq >= 0) {	  free_irq(chip->irq, chip);	}	kfree(chip);	return 0;}static int snd_opti93x_dev_free(struct snd_device *device){	struct snd_opti93x *chip = device->device_data;	return snd_opti93x_free(chip);}static const char *snd_opti93x_chip_id(struct snd_opti93x *codec){	switch (codec->hardware) {	case OPTi9XX_HW_82C930: return "82C930";	case OPTi9XX_HW_82C931: return "82C931";	case OPTi9XX_HW_82C933: return "82C933";	default:		return "???";	}}static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip,			      int dma1, int dma2,			      struct snd_opti93x **rcodec){	static struct snd_device_ops ops = {		.dev_free =	snd_opti93x_dev_free,	};	int error;	struct snd_opti93x *codec;	*rcodec = NULL;	codec = kzalloc(sizeof(*codec), GFP_KERNEL);	if (codec == NULL)		return -ENOMEM;	codec->irq = -1;	codec->dma1 = -1;	codec->dma2 = -1;	if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) {		snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4);		snd_opti93x_free(codec);		return -EBUSY;	}	if (request_dma(dma1, "OPTI93x - 1")) {		snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1);		snd_opti93x_free(codec);		return -EBUSY;	}	codec->dma1 = chip->dma1;	if (request_dma(dma2, "OPTI93x - 2")) {		snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2);		snd_opti93x_free(codec);		return -EBUSY;	}	codec->dma2 = chip->dma2;	if (request_irq(chip->irq, snd_opti93x_interrupt, SA_INTERRUPT, DRIVER_NAME" - WSS", codec)) {		snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);		snd_opti93x_free(codec);		return -EBUSY;	}	codec->card = card;	codec->port = chip->wss_base + 4;	codec->irq = chip->irq;	spin_lock_init(&codec->lock);	codec->hardware = chip->hardware;	codec->chip = chip;	if ((error = snd_opti93x_probe(codec))) {		snd_opti93x_free(codec);		return error;	}	snd_opti93x_init(codec);	/* Register device */	if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) {		snd_opti93x_free(codec);		return error;	}	*rcodec = codec;	return 0;}static struct snd_pcm_ops snd_opti93x_playback_ops = {	.open =		snd_opti93x_playback_open,	.close =	snd_opti93x_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_opti93x_hw_params,	.hw_free =	snd_opti93x_hw_free,	.prepare =	snd_opti93x_playback_prepare,	.trigger =	snd_opti93x_playback_trigger,	.pointer =	snd_opti93x_playback_pointer,};static struct snd_pcm_ops snd_opti93x_capture_ops = {	.open =		snd_opti93x_capture_open,	.close =	snd_opti93x_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_opti93x_hw_params,	.hw_free =	snd_opti93x_hw_free,	.prepare =	snd_opti93x_capture_prepare,	.trigger =	snd_opti93x_capture_trigger,	.pointer =	snd_opti93x_capture_pointer,};static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm){	int error;	struct snd_pcm *pcm;	if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0)		return error;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops);	pcm->private_data = codec;	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;	strcpy(pcm->name, snd_opti93x_chip_id(codec));	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_isa_data(),					      64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024);	codec->pcm = pcm;	if (rpcm)		*rpcm = pcm;	return 0;}/* *  MIXER part */static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	static char *texts[4] = {		"Line1", "Aux", "Mic", "Mix"	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 2;	uinfo->value.enumerated.items = 4;	if (uinfo->value.enumerated.item > 3)		uinfo->value.enumerated.item = 3;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6;	ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6;	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	unsigned short left, right;	int change;		if (ucontrol->value.enumerated.item[0] > 3 ||	    ucontrol->value.enumerated.item[1] > 3)		return -EINVAL;	left = ucontrol->value.enumerated.item[0] << 6;	right = ucontrol->value.enumerated.item[1] << 6;	spin_lock_irqsave(&chip->lock, flags);	left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left;	right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right;	change = left != chip->image[OPTi93X_MIXOUT_LEFT] ||	         right != chip->image[OPTi93X_MIXOUT_RIGHT];	snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left);	snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}#if 0#define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_opti93x_info_single, \  .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert)		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];	return 0;}static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int reg = kcontrol->private_value & 0xff;	int shift = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	int change;	unsigned short val;		val = (ucontrol->value.integer.value[0] & mask);	if (invert)		val = mask - val;	val <<= shift;	spin_lock_irqsave(&chip->lock, flags);	val = (chip->image[reg] & ~(mask << shift)) | val;	change = val != chip->image[reg];	snd_opti93x_out(chip, reg, val);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}#endif /* single */#define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \  .info = snd_opti93x_info_double, \  .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }#define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \	do { xctl.private_value ^= 22; } while (0)#define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \	do { xctl.private_value &= ~0x0000ffff; \	     xctl.private_value |= left_reg | (right_reg << 8); } while (0)static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){	int mask = (kcontrol->private_value >> 24) & 0xff;	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;}static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;		spin_lock_irqsave(&chip->lock, flags);	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;	spin_unlock_irqrestore(&chip->lock, flags);	if (invert) {		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];	}	return 0;}static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int left_reg = kcontrol->private_value & 0xff;	int right_reg = (kcontrol->private_value >> 8) & 0xff;	int shift_left = (kcontrol->private_value >> 16) & 0x07;	int shift_right = (kcontrol->private_value >> 19) & 0x07;	int mask = (kcontrol->private_value >> 24) & 0xff;	int invert = (kcontrol->private_value >> 22) & 1;	int change;	unsigned short val1, val2;		val1 = ucontrol->value.integer.value[0] & mask;	val2 = ucontrol->value.integer.value[1] & mask;	if (invert) {		val1 = mask - val1;		val2 = mask - val2;	}	val1 <<= shift_left;	val2 <<= shift_right;	spin_lock_irqsave(&chip->lock, flags);	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;	change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];	snd_opti93x_out_image(chip, left_reg, val1);	snd_opti93x_out_image(chip, right_reg, val2);	spin_unlock_irqrestore(&chip->lock, flags);	return change;}static struct snd_kcontrol_new snd_opti93x_controls[] = {OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1),OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1),OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1),OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1),OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1),OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0),{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "Capture Source",	.info = snd_opti93x_info_mux,	.get = snd_opti93x_get_mux,	.put = snd_opti93x_put_mux,}};                                        static int snd_opti93x_mixer(struct snd_opti93x *chip){	struct snd_card *card;	struct snd_kcontrol_new knew;

⌨️ 快捷键说明

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