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

📄 maestro3.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	case 0xaa:		/* volume up */		if ((val & 0x7f) > 0)			val--;		if ((val & 0x7f00) > 0)			val -= 0x0100;		chip->ac97->regs[AC97_MASTER_VOL] = val;		outw(val, chip->iobase + CODEC_DATA);		outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       &chip->master_volume->id);		break;	case 0x66:		/* volume down */		if ((val & 0x7f) < 0x1f)			val++;		if ((val & 0x7f00) < 0x1f00)			val += 0x0100;		chip->ac97->regs[AC97_MASTER_VOL] = val;		outw(val, chip->iobase + CODEC_DATA);		outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       &chip->master_volume->id);		break;	}	spin_unlock_irqrestore(&chip->ac97_lock, flags);}static irqreturn_t snd_m3_interrupt(int irq, void *dev_id){	struct snd_m3 *chip = dev_id;	u8 status;	int i;	status = inb(chip->iobase + HOST_INT_STATUS);	if (status == 0xff)		return IRQ_NONE;	if (status & HV_INT_PENDING)		tasklet_hi_schedule(&chip->hwvol_tq);	/*	 * ack an assp int if its running	 * and has an int pending	 */	if (status & ASSP_INT_PENDING) {		u8 ctl = inb(chip->iobase + ASSP_CONTROL_B);		if (!(ctl & STOP_ASSP_CLOCK)) {			ctl = inb(chip->iobase + ASSP_HOST_INT_STATUS);			if (ctl & DSP2HOST_REQ_TIMER) {				outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS);				/* update adc/dac info if it was a timer int */				spin_lock(&chip->reg_lock);				for (i = 0; i < chip->num_substreams; i++) {					struct m3_dma *s = &chip->substreams[i];					if (s->running)						snd_m3_update_ptr(chip, s);				}				spin_unlock(&chip->reg_lock);			}		}	}#if 0 /* TODO: not supported yet */	if ((status & MPU401_INT_PENDING) && chip->rmidi)		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);#endif	/* ack ints */	outb(status, chip->iobase + HOST_INT_STATUS);	return IRQ_HANDLED;}/* */static struct snd_pcm_hardware snd_m3_playback ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 /*SNDRV_PCM_INFO_PAUSE |*/				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(512*1024),	.period_bytes_min =	64,	.period_bytes_max =	(512*1024),	.periods_min =		1,	.periods_max =		1024,};static struct snd_pcm_hardware snd_m3_capture ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 /*SNDRV_PCM_INFO_PAUSE |*/				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(512*1024),	.period_bytes_min =	64,	.period_bytes_max =	(512*1024),	.periods_min =		1,	.periods_max =		1024,};/* */static intsnd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs){	int i;	struct m3_dma *s;	spin_lock_irq(&chip->reg_lock);	for (i = 0; i < chip->num_substreams; i++) {		s = &chip->substreams[i];		if (! s->opened)			goto __found;	}	spin_unlock_irq(&chip->reg_lock);	return -ENOMEM;__found:	s->opened = 1;	s->running = 0;	spin_unlock_irq(&chip->reg_lock);	subs->runtime->private_data = s;	s->substream = subs;	/* set list owners */	if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) {		s->index_list[0] = &chip->mixer_list;	} else		s->index_list[0] = &chip->adc1_list;	s->index_list[1] = &chip->msrc_list;	s->index_list[2] = &chip->dma_list;	return 0;}static voidsnd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs){	struct m3_dma *s = subs->runtime->private_data;	if (s == NULL)		return; /* not opened properly */	spin_lock_irq(&chip->reg_lock);	if (s->substream && s->running)		snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */	if (s->in_lists) {		snd_m3_remove_list(chip, s->index_list[0], s->index[0]);		snd_m3_remove_list(chip, s->index_list[1], s->index[1]);		snd_m3_remove_list(chip, s->index_list[2], s->index[2]);		s->in_lists = 0;	}	s->running = 0;	s->opened = 0;	spin_unlock_irq(&chip->reg_lock);}static intsnd_m3_playback_open(struct snd_pcm_substream *subs){	struct snd_m3 *chip = snd_pcm_substream_chip(subs);	struct snd_pcm_runtime *runtime = subs->runtime;	int err;	if ((err = snd_m3_substream_open(chip, subs)) < 0)		return err;	runtime->hw = snd_m3_playback;	return 0;}static intsnd_m3_playback_close(struct snd_pcm_substream *subs){	struct snd_m3 *chip = snd_pcm_substream_chip(subs);	snd_m3_substream_close(chip, subs);	return 0;}static intsnd_m3_capture_open(struct snd_pcm_substream *subs){	struct snd_m3 *chip = snd_pcm_substream_chip(subs);	struct snd_pcm_runtime *runtime = subs->runtime;	int err;	if ((err = snd_m3_substream_open(chip, subs)) < 0)		return err;	runtime->hw = snd_m3_capture;	return 0;}static intsnd_m3_capture_close(struct snd_pcm_substream *subs){	struct snd_m3 *chip = snd_pcm_substream_chip(subs);	snd_m3_substream_close(chip, subs);	return 0;}/* * create pcm instance */static struct snd_pcm_ops snd_m3_playback_ops = {	.open =		snd_m3_playback_open,	.close =	snd_m3_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_m3_pcm_hw_params,	.hw_free =	snd_m3_pcm_hw_free,	.prepare =	snd_m3_pcm_prepare,	.trigger =	snd_m3_pcm_trigger,	.pointer =	snd_m3_pcm_pointer,};static struct snd_pcm_ops snd_m3_capture_ops = {	.open =		snd_m3_capture_open,	.close =	snd_m3_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_m3_pcm_hw_params,	.hw_free =	snd_m3_pcm_hw_free,	.prepare =	snd_m3_pcm_prepare,	.trigger =	snd_m3_pcm_trigger,	.pointer =	snd_m3_pcm_pointer,};static int __devinitsnd_m3_pcm(struct snd_m3 * chip, int device){	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(chip->card, chip->card->driver, device,			  MAX_PLAYBACKS, MAX_CAPTURES, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_m3_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_m3_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	strcpy(pcm->name, chip->card->driver);	chip->pcm = pcm;		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);	return 0;}/* * ac97 interface *//* * Wait for the ac97 serial bus to be free. * return nonzero if the bus is still busy. */static int snd_m3_ac97_wait(struct snd_m3 *chip){	int i = 10000;	do {		if (! (snd_m3_inb(chip, 0x30) & 1))			return 0;		cpu_relax();	} while (i-- > 0);	snd_printk(KERN_ERR "ac97 serial bus busy\n");	return 1;}static unsigned shortsnd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg){	struct snd_m3 *chip = ac97->private_data;	unsigned long flags;	unsigned short data = 0xffff;	if (snd_m3_ac97_wait(chip))		goto fail;	spin_lock_irqsave(&chip->ac97_lock, flags);	snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);	if (snd_m3_ac97_wait(chip))		goto fail_unlock;	data = snd_m3_inw(chip, CODEC_DATA);fail_unlock:	spin_unlock_irqrestore(&chip->ac97_lock, flags);fail:	return data;}static voidsnd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val){	struct snd_m3 *chip = ac97->private_data;	unsigned long flags;	if (snd_m3_ac97_wait(chip))		return;	spin_lock_irqsave(&chip->ac97_lock, flags);	snd_m3_outw(chip, val, CODEC_DATA);	snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);	spin_unlock_irqrestore(&chip->ac97_lock, flags);}static void snd_m3_remote_codec_config(int io, int isremote){	isremote = isremote ? 1 : 0;	outw((inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,	     io + RING_BUS_CTRL_B);	outw((inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,	     io + SDO_OUT_DEST_CTRL);	outw((inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,	     io + SDO_IN_DEST_CTRL);}/*  * hack, returns non zero on err  */static int snd_m3_try_read_vendor(struct snd_m3 *chip){	u16 ret;	if (snd_m3_ac97_wait(chip))		return 1;	snd_m3_outb(chip, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);	if (snd_m3_ac97_wait(chip))		return 1;	ret = snd_m3_inw(chip, 0x32);	return (ret == 0) || (ret == 0xffff);}static void snd_m3_ac97_reset(struct snd_m3 *chip){	u16 dir;	int delay1 = 0, delay2 = 0, i;	int io = chip->iobase;	if (chip->allegro_flag) {		/*		 * the onboard codec on the allegro seems 		 * to want to wait a very long time before		 * coming back to life 		 */		delay1 = 50;		delay2 = 800;	} else {		/* maestro3 */		delay1 = 20;		delay2 = 500;	}	for (i = 0; i < 5; i++) {		dir = inw(io + GPIO_DIRECTION);		if (!chip->irda_workaround)			dir |= 0x10; /* assuming pci bus master? */		snd_m3_remote_codec_config(io, 0);		outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);		udelay(20);		outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);		outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);		outw(0, io + GPIO_DATA);		outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);		schedule_timeout_uninterruptib

⌨️ 快捷键说明

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