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

📄 intel8x0.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	return ioread32(chip->bmaddr + offset);}static inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val){	iowrite8(val, chip->bmaddr + offset);}static inline void iputword(struct intel8x0 *chip, u32 offset, u16 val){	iowrite16(val, chip->bmaddr + offset);}static inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val){	iowrite32(val, chip->bmaddr + offset);}/* *  Lowlevel I/O - AC'97 registers */static inline u16 iagetword(struct intel8x0 *chip, u32 offset){	return ioread16(chip->addr + offset);}static inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val){	iowrite16(val, chip->addr + offset);}/* *  Basic I/O *//* * access to AC97 codec via normal i/o (for ICH and SIS7012) */static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec){	int time;		if (codec > 2)		return -EIO;	if (chip->in_sdin_init) {		/* we don't know the ready bit assignment at the moment */		/* so we check any */		codec = chip->codec_isr_bits;	} else {		codec = chip->codec_bit[chip->ac97_sdin[codec]];	}	/* codec ready ? */	if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0)		return -EIO;	if (chip->buggy_semaphore)		return 0; /* just ignore ... */	/* Anyone holding a semaphore for 1 msec should be shot... */	time = 100;      	do {      		if (!(igetbyte(chip, ICHREG(ACC_SEMA)) & ICH_CAS))      			return 0;		udelay(10);	} while (time--);	/* access to some forbidden (non existant) ac97 registers will not	 * reset the semaphore. So even if you don't get the semaphore, still	 * continue the access. We don't need the semaphore anyway. */	snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",			igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA)));	iagetword(chip, 0);	/* clear semaphore flag */	/* I don't care about the semaphore */	return -EBUSY;} static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,				     unsigned short reg,				     unsigned short val){	struct intel8x0 *chip = ac97->private_data;		if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {		if (! chip->in_ac97_init)			snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);	}	iaputword(chip, reg + ac97->num * 0x80, val);}static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,					      unsigned short reg){	struct intel8x0 *chip = ac97->private_data;	unsigned short res;	unsigned int tmp;	if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {		if (! chip->in_ac97_init)			snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);		res = 0xffff;	} else {		res = iagetword(chip, reg + ac97->num * 0x80);		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {			/* reset RCS and preserve other R/WC bits */			iputdword(chip, ICHREG(GLOB_STA), tmp &				  ~(chip->codec_ready_bits | ICH_GSCI));			if (! chip->in_ac97_init)				snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);			res = 0xffff;		}	}	return res;}static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip,						   unsigned int codec){	unsigned int tmp;	if (snd_intel8x0_codec_semaphore(chip, codec) >= 0) {		iagetword(chip, codec * 0x80);		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {			/* reset RCS and preserve other R/WC bits */			iputdword(chip, ICHREG(GLOB_STA), tmp &				  ~(chip->codec_ready_bits | ICH_GSCI));		}	}}/* * access to AC97 for Ali5455 */static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask){	int count = 0;	for (count = 0; count < 0x7f; count++) {		int val = igetbyte(chip, ICHREG(ALI_CSPSR));		if (val & mask)			return 0;	}	if (! chip->in_ac97_init)		snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n");	return -EBUSY;}static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip){	int time = 100;	if (chip->buggy_semaphore)		return 0; /* just ignore ... */	while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))		udelay(1);	if (! time && ! chip->in_ac97_init)		snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");	return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY);}static unsigned short snd_intel8x0_ali_codec_read(struct snd_ac97 *ac97, unsigned short reg){	struct intel8x0 *chip = ac97->private_data;	unsigned short data = 0xffff;	if (snd_intel8x0_ali_codec_semaphore(chip))		goto __err;	reg |= ALI_CPR_ADDR_READ;	if (ac97->num)		reg |= ALI_CPR_ADDR_SECONDARY;	iputword(chip, ICHREG(ALI_CPR_ADDR), reg);	if (snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_READ_OK))		goto __err;	data = igetword(chip, ICHREG(ALI_SPR)); __err:	return data;}static void snd_intel8x0_ali_codec_write(struct snd_ac97 *ac97, unsigned short reg,					 unsigned short val){	struct intel8x0 *chip = ac97->private_data;	if (snd_intel8x0_ali_codec_semaphore(chip))		return;	iputword(chip, ICHREG(ALI_CPR), val);	if (ac97->num)		reg |= ALI_CPR_ADDR_SECONDARY;	iputword(chip, ICHREG(ALI_CPR_ADDR), reg);	snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_WRITE_OK);}/* * DMA I/O */static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ichdev) {	int idx;	u32 *bdbar = ichdev->bdbar;	unsigned long port = ichdev->reg_offset;	iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);	if (ichdev->size == ichdev->fragsize) {		ichdev->ack_reload = ichdev->ack = 2;		ichdev->fragsize1 = ichdev->fragsize >> 1;		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) {			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf);			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */						     ichdev->fragsize1 >> ichdev->pos_shift);			bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1));			bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */						     ichdev->fragsize1 >> ichdev->pos_shift);		}		ichdev->frags = 2;	} else {		ichdev->ack_reload = ichdev->ack = 1;		ichdev->fragsize1 = ichdev->fragsize;		for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) {			bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf +						     (((idx >> 1) * ichdev->fragsize) %						      ichdev->size));			bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */						     ichdev->fragsize >> ichdev->pos_shift);#if 0			printk("bdbar[%i] = 0x%x [0x%x]\n",			       idx + 0, bdbar[idx + 0], bdbar[idx + 1]);#endif		}		ichdev->frags = ichdev->size / ichdev->fragsize;	}	iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK);	ichdev->civ = 0;	iputbyte(chip, port + ICH_REG_OFF_CIV, 0);	ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;	ichdev->position = 0;#if 0	printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",			ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);#endif	/* clear interrupts */	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);}#ifdef __i386__/* * Intel 82443MX running a 100MHz processor system bus has a hardware bug, * which aborts PCI busmaster for audio transfer.  A workaround is to set * the pages as non-cached.  For details, see the errata in *	http://www.intel.com/design/chipsets/specupdt/245051.htm */static void fill_nocache(void *buf, int size, int nocache){	size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;	change_page_attr(virt_to_page(buf), size, nocache ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL);	global_flush_tlb();}#else#define fill_nocache(buf,size,nocache)#endif/* *  Interrupt handler */static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ichdev){	unsigned long port = ichdev->reg_offset;	unsigned long flags;	int status, civ, i, step;	int ack = 0;	spin_lock_irqsave(&chip->reg_lock, flags);	status = igetbyte(chip, port + ichdev->roff_sr);	civ = igetbyte(chip, port + ICH_REG_OFF_CIV);	if (!(status & ICH_BCIS)) {		step = 0;	} else if (civ == ichdev->civ) {		// snd_printd("civ same %d\n", civ);		step = 1;		ichdev->civ++;		ichdev->civ &= ICH_REG_LVI_MASK;	} else {		step = civ - ichdev->civ;		if (step < 0)			step += ICH_REG_LVI_MASK + 1;		// if (step != 1)		//	snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ);		ichdev->civ = civ;	}	ichdev->position += step * ichdev->fragsize1;	if (! chip->in_measurement)		ichdev->position %= ichdev->size;	ichdev->lvi += step;	ichdev->lvi &= ICH_REG_LVI_MASK;	iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);	for (i = 0; i < step; i++) {		ichdev->lvi_frag++;		ichdev->lvi_frag %= ichdev->frags;		ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);#if 0	printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",	       ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2],	       ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port),	       inl(port + 4), inb(port + ICH_REG_OFF_CR));#endif		if (--ichdev->ack == 0) {			ichdev->ack = ichdev->ack_reload;			ack = 1;		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	if (ack && ichdev->substream) {		snd_pcm_period_elapsed(ichdev->substream);	}	iputbyte(chip, port + ichdev->roff_sr,		 status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI));}static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id){	struct intel8x0 *chip = dev_id;	struct ichdev *ichdev;	unsigned int status;	unsigned int i;	status = igetdword(chip, chip->int_sta_reg);	if (status == 0xffffffff)	/* we are not yet resumed */		return IRQ_NONE;	if ((status & chip->int_sta_mask) == 0) {		if (status) {			/* ack */			iputdword(chip, chip->int_sta_reg, status);			if (! chip->buggy_irq)				status = 0;		}		return IRQ_RETVAL(status);	}	for (i = 0; i < chip->bdbars_count; i++) {		ichdev = &chip->ichd[i];		if (status & ichdev->int_sta_mask)			snd_intel8x0_update(chip, ichdev);	}	/* ack them */	iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask);		return IRQ_HANDLED;}/* *  PCM part */static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	struct intel8x0 *chip = snd_pcm_substream_chip(substream);	struct ichdev *ichdev = get_ichdev(substream);	unsigned char val = 0;	unsigned long port = ichdev->reg_offset;	switch (cmd) {	case SNDRV_PCM_TRIGGER_RESUME:		ichdev->suspended = 0;		/* fallthru */	case SNDRV_PCM_TRIGGER_START:		val = ICH_IOCE | ICH_STARTBM;		break;	case SNDRV_PCM_TRIGGER_SUSPEND:		ichdev->suspended = 1;		/* fallthru */	case SNDRV_PCM_TRIGGER_STOP:		val = 0;		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		val = ICH_IOCE;		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		val = ICH_IOCE | ICH_STARTBM;		break;	default:		return -EINVAL;	}	iputbyte(chip, port + ICH_REG_OFF_CR, val);	if (cmd == SNDRV_PCM_TRIGGER_STOP) {		/* wait until DMA stopped */		while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ;		/* reset whole DMA things */		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);	}	return 0;}static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd){	struct intel8x0 *chip = snd_pcm_substream_chip(substream);	struct ichdev *ichdev = get_ichdev(substream);	unsigned long port = ichdev->reg_offset;	static int fiforeg[] = {		ICHREG(ALI_FIFOCR1), ICHREG(ALI_FIFOCR2), ICHREG(ALI_FIFOCR3)	};	unsigned int val, fifo;	val = igetdword(chip, ICHREG(ALI_DMACR));	switch (cmd) {	case SNDRV_PCM_TRIGGER_RESUME:		ichdev->suspended = 0;		/* fallthru */	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {			/* clear FIFO for synchronization of channels */			fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);			fifo &= ~(0xff << (ichdev->ali_slot % 4));  			fifo |= 0x83 << (ichdev->ali_slot % 4); 			iputdword(chip, fiforeg[ichdev->ali_slot / 4], fifo);		}		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);		val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */		/* start DMA */		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot));		break;	case SNDRV_PCM_TRIGGER_SUSPEND:		ichdev->suspended = 1;		/* fallthru */	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		/* pause */		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16)));		iputbyte(chip, port + ICH_REG_OFF_CR, 0);		while (igetbyte(chip, port + ICH_REG_OFF_CR))			;		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)			break;		/* reset whole DMA things */		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);		/* clear interrupts */		iputbyte(chip, port + ICH_REG_OFF_SR,			 igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e);		iputdword(chip, ICHREG(ALI_INTERRUPTSR),			  igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ichdev->int_sta_mask);		break;	default:		return -EINVAL;	}	return 0;}static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,				  struct snd_pcm_hw_params *hw_params){	struct intel8x0 *chip = snd_pcm_substream_chip(substream);	struct ichdev *ichdev = get_ichdev(substream);	struct snd_pcm_runtime *runtime = substream->runtime;

⌨️ 快捷键说明

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