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

📄 hda_intel.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	wp = azx_readb(chip, CORBWP);	wp++;	wp %= ICH6_MAX_CORB_ENTRIES;	spin_lock_irq(&chip->reg_lock);	chip->rirb.cmds++;	chip->corb.buf[wp] = cpu_to_le32(val);	azx_writel(chip, CORBWP, wp);	spin_unlock_irq(&chip->reg_lock);	return 0;}#define ICH6_RIRB_EX_UNSOL_EV	(1<<4)/* retrieve RIRB entry - called from interrupt handler */static void azx_update_rirb(struct azx *chip){	unsigned int rp, wp;	u32 res, res_ex;	wp = azx_readb(chip, RIRBWP);	if (wp == chip->rirb.wp)		return;	chip->rirb.wp = wp;			while (chip->rirb.rp != wp) {		chip->rirb.rp++;		chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES;		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);		res = le32_to_cpu(chip->rirb.buf[rp]);		if (res_ex & ICH6_RIRB_EX_UNSOL_EV)			snd_hda_queue_unsol_event(chip->bus, res, res_ex);		else if (chip->rirb.cmds) {			chip->rirb.cmds--;			chip->rirb.res = res;		}	}}/* receive a response */static unsigned int azx_rirb_get_response(struct hda_codec *codec){	struct azx *chip = codec->bus->private_data;	unsigned long timeout; again:	timeout = jiffies + msecs_to_jiffies(1000);	do {		if (chip->polling_mode) {			spin_lock_irq(&chip->reg_lock);			azx_update_rirb(chip);			spin_unlock_irq(&chip->reg_lock);		}		if (!chip->rirb.cmds)			return chip->rirb.res; /* the last value */		schedule_timeout_uninterruptible(1);	} while (time_after_eq(timeout, jiffies));	if (chip->msi) {		snd_printk(KERN_WARNING "hda_intel: No response from codec, "			   "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);		free_irq(chip->irq, chip);		chip->irq = -1;		pci_disable_msi(chip->pci);		chip->msi = 0;		if (azx_acquire_irq(chip, 1) < 0)			return -1;		goto again;	}	if (!chip->polling_mode) {		snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "			   "switching to polling mode: last cmd=0x%08x\n",			   chip->last_cmd);		chip->polling_mode = 1;		goto again;	}	snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "		   "switching to single_cmd mode: last cmd=0x%08x\n",		   chip->last_cmd);	chip->rirb.rp = azx_readb(chip, RIRBWP);	chip->rirb.cmds = 0;	/* switch to single_cmd mode */	chip->single_cmd = 1;	azx_free_cmd_io(chip);	return -1;}/* * Use the single immediate command instead of CORB/RIRB for simplicity * * Note: according to Intel, this is not preferred use.  The command was *       intended for the BIOS only, and may get confused with unsolicited *       responses.  So, we shouldn't use it for normal operation from the *       driver. *       I left the codes, however, for debugging/testing purposes. *//* send a command */static int azx_single_send_cmd(struct hda_codec *codec, u32 val){	struct azx *chip = codec->bus->private_data;	int timeout = 50;	while (timeout--) {		/* check ICB busy bit */		if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) {			/* Clear IRV valid bit */			azx_writew(chip, IRS, azx_readw(chip, IRS) |				   ICH6_IRS_VALID);			azx_writel(chip, IC, val);			azx_writew(chip, IRS, azx_readw(chip, IRS) |				   ICH6_IRS_BUSY);			return 0;		}		udelay(1);	}	snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",		   azx_readw(chip, IRS), val);	return -EIO;}/* receive a response */static unsigned int azx_single_get_response(struct hda_codec *codec){	struct azx *chip = codec->bus->private_data;	int timeout = 50;	while (timeout--) {		/* check IRV busy bit */		if (azx_readw(chip, IRS) & ICH6_IRS_VALID)			return azx_readl(chip, IR);		udelay(1);	}	snd_printd(SFX "get_response timeout: IRS=0x%x\n",		   azx_readw(chip, IRS));	return (unsigned int)-1;}/* * The below are the main callbacks from hda_codec. * * They are just the skeleton to call sub-callbacks according to the * current setting of chip->single_cmd. *//* send a command */static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,			int direct, unsigned int verb,			unsigned int para){	struct azx *chip = codec->bus->private_data;	u32 val;	val = (u32)(codec->addr & 0x0f) << 28;	val |= (u32)direct << 27;	val |= (u32)nid << 20;	val |= verb << 8;	val |= para;	chip->last_cmd = val;	if (chip->single_cmd)		return azx_single_send_cmd(codec, val);	else		return azx_corb_send_cmd(codec, val);}/* get a response */static unsigned int azx_get_response(struct hda_codec *codec){	struct azx *chip = codec->bus->private_data;	if (chip->single_cmd)		return azx_single_get_response(codec);	else		return azx_rirb_get_response(codec);}#ifdef CONFIG_SND_HDA_POWER_SAVEstatic void azx_power_notify(struct hda_codec *codec);#endif/* reset codec link */static int azx_reset(struct azx *chip){	int count;	/* clear STATESTS */	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);	/* reset controller */	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);	count = 50;	while (azx_readb(chip, GCTL) && --count)		msleep(1);	/* delay for >= 100us for codec PLL to settle per spec	 * Rev 0.9 section 5.5.1	 */	msleep(1);	/* Bring controller out of reset */	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);	count = 50;	while (!azx_readb(chip, GCTL) && --count)		msleep(1);	/* Brent Chartrand said to wait >= 540us for codecs to initialize */	msleep(1);	/* check to see if controller is ready */	if (!azx_readb(chip, GCTL)) {		snd_printd("azx_reset: controller not ready!\n");		return -EBUSY;	}	/* Accept unsolicited responses */	azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);	/* detect codecs */	if (!chip->codec_mask) {		chip->codec_mask = azx_readw(chip, STATESTS);		snd_printdd("codec_mask = 0x%x\n", chip->codec_mask);	}	return 0;}/* * Lowlevel interface */  /* enable interrupts */static void azx_int_enable(struct azx *chip){	/* enable controller CIE and GIE */	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |		   ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN);}/* disable interrupts */static void azx_int_disable(struct azx *chip){	int i;	/* disable interrupts in stream descriptor */	for (i = 0; i < chip->num_streams; i++) {		struct azx_dev *azx_dev = &chip->azx_dev[i];		azx_sd_writeb(azx_dev, SD_CTL,			      azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);	}	/* disable SIE for all streams */	azx_writeb(chip, INTCTL, 0);	/* disable controller CIE and GIE */	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &		   ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN));}/* clear interrupts */static void azx_int_clear(struct azx *chip){	int i;	/* clear stream status */	for (i = 0; i < chip->num_streams; i++) {		struct azx_dev *azx_dev = &chip->azx_dev[i];		azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);	}	/* clear STATESTS */	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);	/* clear rirb status */	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);	/* clear int status */	azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM);}/* start a stream */static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev){	/* enable SIE */	azx_writeb(chip, INTCTL,		   azx_readb(chip, INTCTL) | (1 << azx_dev->index));	/* set DMA start and interrupt mask */	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |		      SD_CTL_DMA_START | SD_INT_MASK);}/* stop a stream */static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev){	/* stop DMA */	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &		      ~(SD_CTL_DMA_START | SD_INT_MASK));	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */	/* disable SIE */	azx_writeb(chip, INTCTL,		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));}/* * reset and start the controller registers */static void azx_init_chip(struct azx *chip){	if (chip->initialized)		return;	/* reset controller */	azx_reset(chip);	/* initialize interrupts */	azx_int_clear(chip);	azx_int_enable(chip);	/* initialize the codec command I/O */	if (!chip->single_cmd)		azx_init_cmd_io(chip);	/* program the position buffer */	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);	azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));	chip->initialized = 1;}/* * initialize the PCI registers *//* update bits in a PCI register byte */static void update_pci_byte(struct pci_dev *pci, unsigned int reg,			    unsigned char mask, unsigned char val){	unsigned char data;	pci_read_config_byte(pci, reg, &data);	data &= ~mask;	data |= (val & mask);	pci_write_config_byte(pci, reg, data);}static void azx_init_pci(struct azx *chip){	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS	 * Ensuring these bits are 0 clears playback static on some HD Audio	 * codecs	 */	update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);	switch (chip->driver_type) {	case AZX_DRIVER_ATI:		/* For ATI SB450 azalia HD audio, we need to enable snoop */		update_pci_byte(chip->pci,				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 				0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);		break;	case AZX_DRIVER_NVIDIA:		/* For NVIDIA HDA, enable snoop */		update_pci_byte(chip->pci,				NVIDIA_HDA_TRANSREG_ADDR,				0x0f, NVIDIA_HDA_ENABLE_COHBITS);		break;        }}/* * interrupt handler */static irqreturn_t azx_interrupt(int irq, void *dev_id){	struct azx *chip = dev_id;	struct azx_dev *azx_dev;	u32 status;	int i;	spin_lock(&chip->reg_lock);	status = azx_readl(chip, INTSTS);	if (status == 0) {		spin_unlock(&chip->reg_lock);		return IRQ_NONE;	}		for (i = 0; i < chip->num_streams; i++) {		azx_dev = &chip->azx_dev[i];		if (status & azx_dev->sd_int_sta_mask) {			azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);			if (azx_dev->substream && azx_dev->running) {				azx_dev->period_intr++;				spin_unlock(&chip->reg_lock);				snd_pcm_period_elapsed(azx_dev->substream);				spin_lock(&chip->reg_lock);			}		}	}	/* clear rirb int */	status = azx_readb(chip, RIRBSTS);	if (status & RIRB_INT_MASK) {		if (!chip->single_cmd && (status & RIRB_INT_RESPONSE))			azx_update_rirb(chip);		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);	}#if 0	/* clear state status int */	if (azx_readb(chip, STATESTS) & 0x04)		azx_writeb(chip, STATESTS, 0x04);#endif	spin_unlock(&chip->reg_lock);		return IRQ_HANDLED;}/* * set up BDL entries */static void azx_setup_periods(struct azx_dev *azx_dev){	u32 *bdl = azx_dev->bdl;	dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;	int idx;	/* reset BDL address */	azx_sd_writel(azx_dev, SD_BDLPL, 0);	azx_sd_writel(azx_dev, SD_BDLPU, 0);	/* program the initial BDL entries */	for (idx = 0; idx < azx_dev->frags; idx++) {		unsigned int off = idx << 2; /* 4 dword step */		dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;		/* program the address field of the BDL entry */		bdl[off] = cpu_to_le32((u32)addr);		bdl[off+1] = cpu_to_le32(upper_32bit(addr));		/* program the size field of the BDL entry */		bdl[off+2] = cpu_to_le32(azx_dev->fragsize);		/* program the IOC to enable interrupt when buffer completes */		bdl[off+3] = cpu_to_le32(0x01);	}}/* * set up the SD for streaming */static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev){	unsigned char val;	int timeout;	/* make sure the run bit is zero for SD */	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &		      ~SD_CTL_DMA_START);	/* reset stream */	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |		      SD_CTL_STREAM_RESET);	udelay(3);	timeout = 300;	while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&	       --timeout)		;	val &= ~SD_CTL_STREAM_RESET;	azx_sd_writeb(azx_dev, SD_CTL, val);	udelay(3);	timeout = 300;	/* waiting for hardware to report that the stream is out of reset */	while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&	       --timeout)		;	/* program the stream_tag */	azx_sd_writel(azx_dev, SD_CTL,		      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|		      (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT));	/* program the length of samples in cyclic buffer */	azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);	/* program the stream format */	/* this value needs to be the same as the one programmed */	azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val);	/* program the stream LVI (last valid index) of the BDL */

⌨️ 快捷键说明

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