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

📄 pcxhr_core.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Driver for Digigram pcxhr compatible soundcards * * low level interface with interrupt and message handling implementation * * Copyright (c) 2004 by Digigram <alsa@digigram.com> * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */#include <sound/driver.h>#include <linux/delay.h>#include <linux/firmware.h>#include <linux/interrupt.h>#include <asm/io.h>#include <sound/core.h>#include "pcxhr.h"#include "pcxhr_mixer.h"#include "pcxhr_hwdep.h"#include "pcxhr_core.h"/* registers used on the PLX (port 1) */#define PCXHR_PLX_OFFSET_MIN	0x40#define PCXHR_PLX_MBOX0		0x40#define PCXHR_PLX_MBOX1		0x44#define PCXHR_PLX_MBOX2		0x48#define PCXHR_PLX_MBOX3		0x4C#define PCXHR_PLX_MBOX4		0x50#define PCXHR_PLX_MBOX5		0x54#define PCXHR_PLX_MBOX6		0x58#define PCXHR_PLX_MBOX7		0x5C#define PCXHR_PLX_L2PCIDB	0x64#define PCXHR_PLX_IRQCS		0x68#define PCXHR_PLX_CHIPSC	0x6C/* registers used on the DSP (port 2) */#define PCXHR_DSP_ICR		0x00#define PCXHR_DSP_CVR		0x04#define PCXHR_DSP_ISR		0x08#define PCXHR_DSP_IVR		0x0C#define PCXHR_DSP_RXH		0x14#define PCXHR_DSP_TXH		0x14#define PCXHR_DSP_RXM		0x18#define PCXHR_DSP_TXM		0x18#define PCXHR_DSP_RXL		0x1C#define PCXHR_DSP_TXL		0x1C#define PCXHR_DSP_RESET		0x20#define PCXHR_DSP_OFFSET_MAX	0x20/* access to the card */#define PCXHR_PLX 1#define PCXHR_DSP 2#if (PCXHR_DSP_OFFSET_MAX > PCXHR_PLX_OFFSET_MIN)#undef  PCXHR_REG_TO_PORT(x)#else#define PCXHR_REG_TO_PORT(x)	((x)>PCXHR_DSP_OFFSET_MAX ? PCXHR_PLX : PCXHR_DSP)#endif#define PCXHR_INPB(mgr,x)	inb((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))#define PCXHR_INPL(mgr,x)	inl((mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))#define PCXHR_OUTPB(mgr,x,data)	outb((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))#define PCXHR_OUTPL(mgr,x,data)	outl((data), (mgr)->port[PCXHR_REG_TO_PORT(x)] + (x))/* attention : access the PCXHR_DSP_* registers with inb and outb only ! *//* params used with PCXHR_PLX_MBOX0 */#define PCXHR_MBOX0_HF5			(1 << 0)#define PCXHR_MBOX0_HF4			(1 << 1)#define PCXHR_MBOX0_BOOT_HERE		(1 << 23)/* params used with PCXHR_PLX_IRQCS */#define PCXHR_IRQCS_ENABLE_PCIIRQ	(1 << 8)#define PCXHR_IRQCS_ENABLE_PCIDB	(1 << 9)#define PCXHR_IRQCS_ACTIVE_PCIDB	(1 << 13)/* params used with PCXHR_PLX_CHIPSC */#define PCXHR_CHIPSC_INIT_VALUE		0x100D767E#define PCXHR_CHIPSC_RESET_XILINX	(1 << 16)#define PCXHR_CHIPSC_GPI_USERI		(1 << 17)#define PCXHR_CHIPSC_DATA_CLK		(1 << 24)#define PCXHR_CHIPSC_DATA_IN		(1 << 26)/* params used with PCXHR_DSP_ICR */#define PCXHR_ICR_HI08_RREQ		0x01#define PCXHR_ICR_HI08_TREQ		0x02#define PCXHR_ICR_HI08_HDRQ		0x04#define PCXHR_ICR_HI08_HF0		0x08#define PCXHR_ICR_HI08_HF1		0x10#define PCXHR_ICR_HI08_HLEND		0x20#define PCXHR_ICR_HI08_INIT		0x80/* params used with PCXHR_DSP_CVR */#define PCXHR_CVR_HI08_HC		0x80/* params used with PCXHR_DSP_ISR */#define PCXHR_ISR_HI08_RXDF		0x01#define PCXHR_ISR_HI08_TXDE		0x02#define PCXHR_ISR_HI08_TRDY		0x04#define PCXHR_ISR_HI08_ERR		0x08#define PCXHR_ISR_HI08_CHK		0x10#define PCXHR_ISR_HI08_HREQ		0x80/* constants used for delay in msec */#define PCXHR_WAIT_DEFAULT		2#define PCXHR_WAIT_IT			25#define PCXHR_WAIT_IT_EXTRA		65/* * pcxhr_check_reg_bit - wait for the specified bit is set/reset on a register * @reg: register to check * @mask: bit mask * @bit: resultant bit to be checked * @time: time-out of loop in msec * * returns zero if a bit matches, or a negative error code. */static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg,			       unsigned char mask, unsigned char bit, int time,			       unsigned char* read){	int i = 0;	unsigned long end_time = jiffies + (time * HZ + 999) / 1000;	do {		*read = PCXHR_INPB(mgr, reg);		if ((*read & mask) == bit) {			if (i > 100)				snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n",					    reg, i);			return 0;		}		i++;	} while (time_after_eq(end_time, jiffies));	snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n",		   reg, mask, *read);	return -EIO;}/* constants used with pcxhr_check_reg_bit() */#define PCXHR_TIMEOUT_DSP		200#define PCXHR_MASK_EXTRA_INFO		0x0000FE#define PCXHR_MASK_IT_HF0		0x000100#define PCXHR_MASK_IT_HF1		0x000200#define PCXHR_MASK_IT_NO_HF0_HF1	0x000400#define PCXHR_MASK_IT_MANAGE_HF5	0x000800#define PCXHR_MASK_IT_WAIT		0x010000#define PCXHR_MASK_IT_WAIT_EXTRA	0x020000#define PCXHR_IT_SEND_BYTE_XILINX	(0x0000003C | PCXHR_MASK_IT_HF0)#define PCXHR_IT_TEST_XILINX		(0x0000003C | PCXHR_MASK_IT_HF1 | \					 PCXHR_MASK_IT_MANAGE_HF5)#define PCXHR_IT_DOWNLOAD_BOOT		(0x0000000C | PCXHR_MASK_IT_HF1 | \					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)#define PCXHR_IT_RESET_BOARD_FUNC	(0x0000000C | PCXHR_MASK_IT_HF0 | \					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA)#define PCXHR_IT_DOWNLOAD_DSP		(0x0000000C | \					 PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT)#define PCXHR_IT_DEBUG			(0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1)#define PCXHR_IT_RESET_SEMAPHORE	(0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1)#define PCXHR_IT_MESSAGE		(0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1)#define PCXHR_IT_RESET_CHK		(0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1)#define PCXHR_IT_UPDATE_RBUFFER		(0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1)static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic){	int err;	unsigned char reg;	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {		/* clear hf5 bit */		PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,			    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);	}	if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) {		reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;		if (itdsp & PCXHR_MASK_IT_HF0)			reg |= PCXHR_ICR_HI08_HF0;		if (itdsp & PCXHR_MASK_IT_HF1)			reg |= PCXHR_ICR_HI08_HF1;		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);	}	reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC);	PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg);	if (itdsp & PCXHR_MASK_IT_WAIT) {		if (atomic)			mdelay(PCXHR_WAIT_IT);		else			msleep(PCXHR_WAIT_IT);	}	if (itdsp & PCXHR_MASK_IT_WAIT_EXTRA) {		if (atomic)			mdelay(PCXHR_WAIT_IT_EXTRA);		else			msleep(PCXHR_WAIT_IT);	}	/* wait for CVR_HI08_HC == 0 */	err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR,  PCXHR_CVR_HI08_HC, 0,				  PCXHR_TIMEOUT_DSP, &reg);	if (err) {		snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT CVR\n");		return err;	}	if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) {		/* wait for hf5 bit */		err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5,					  PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, &reg);		if (err) {			snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n");			return err;		}	}	return 0; /* retry not handled here */}void pcxhr_reset_xilinx_com(struct pcxhr_mgr *mgr){	/* reset second xilinx */	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC,		    PCXHR_CHIPSC_INIT_VALUE & ~PCXHR_CHIPSC_RESET_XILINX);}static void pcxhr_enable_irq(struct pcxhr_mgr *mgr, int enable){	unsigned int reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);	/* enable/disable interrupts */	if (enable)		reg |=  (PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);	else		reg &= ~(PCXHR_IRQCS_ENABLE_PCIIRQ | PCXHR_IRQCS_ENABLE_PCIDB);	PCXHR_OUTPL(mgr, PCXHR_PLX_IRQCS, reg);}void pcxhr_reset_dsp(struct pcxhr_mgr *mgr){	/* disable interrupts */	pcxhr_enable_irq(mgr, 0);	/* let's reset the DSP */	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 0);	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */	PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, 3);	msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */	/* reset mailbox */	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, 0);}void pcxhr_enable_dsp(struct pcxhr_mgr *mgr){	/* enable interrupts */	pcxhr_enable_irq(mgr, 1);}/* * load the xilinx image */int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second){	unsigned int i;	unsigned int chipsc;	unsigned char data;	unsigned char mask;	unsigned char *image;	/* test first xilinx */	chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC);	if (!second) {		if (chipsc & PCXHR_CHIPSC_GPI_USERI) {			snd_printdd("no need to load first xilinx\n");			return 0; /* first xilinx is already present and cannot be reset */		}	} else {		if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) {			snd_printk(KERN_ERR "error loading first xilinx\n");			return -EINVAL;		}		/* activate second xilinx */		chipsc |= PCXHR_CHIPSC_RESET_XILINX;		PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);		msleep( PCXHR_WAIT_DEFAULT ); /* wait 2 msec */	}	image = xilinx->data;	for (i = 0; i < xilinx->size; i++, image++) {		data = *image;		mask = 0x80;		while (mask) {			chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);			if (data & mask)				chipsc |= PCXHR_CHIPSC_DATA_IN;			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);			chipsc |= PCXHR_CHIPSC_DATA_CLK;			PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);			mask >>= 1;		}		/* don't take too much time in this loop... */		cond_resched();	}	chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN);	PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc);	/* wait 2 msec (time to boot the xilinx before any access) */	msleep( PCXHR_WAIT_DEFAULT );	return 0;}/* * send an executable file to the DSP */static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp){	int err;	unsigned int i;	unsigned int len;	unsigned char *data;	unsigned char dummy;	/* check the length of boot image */	snd_assert(dsp->size > 0, return -EINVAL);	snd_assert(dsp->size % 3 == 0, return -EINVAL);	snd_assert(dsp->data, return -EINVAL);	/* transfert data buffer from PC to DSP */	for (i = 0; i < dsp->size; i += 3) {		data = dsp->data + i;		if (i == 0) {			/* test data header consistency */			len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]);			snd_assert((len==0) || (dsp->size == (len+2)*3), return -EINVAL);		}		/* wait DSP ready for new transfer */		err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY,					  PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy);		if (err) {			snd_printk(KERN_ERR "dsp loading error at position %d\n", i);			return err;		}		/* send host data */		PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, data[0]);		PCXHR_OUTPB(mgr, PCXHR_DSP_TXM, data[1]);		PCXHR_OUTPB(mgr, PCXHR_DSP_TXL, data[2]);		/* don't take too much time in this loop... */		cond_resched();	}	/* give some time to boot the DSP */	msleep(PCXHR_WAIT_DEFAULT);	return 0;}/* * load the eeprom image */int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom){	int err;	unsigned char reg;	/* init value of the ICR register */	reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ;	if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) {		/* no need to load the eeprom binary, but init the HI08 interface */		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT);		msleep(PCXHR_WAIT_DEFAULT);		PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);		msleep(PCXHR_WAIT_DEFAULT);		snd_printdd("no need to load eeprom boot\n");		return 0;	}	PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg);	err = pcxhr_download_dsp(mgr, eeprom);	if (err)		return err;	/* wait for chk bit */	return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK,				   PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &reg);}/* * load the boot image */int pcxhr_load_boot_binary(struct pcxhr_mgr *mgr, const struct firmware *boot){	int err;	unsigned int physaddr = mgr->hostport.addr;	unsigned char dummy;	/* send the hostport address to the DSP (only the upper 24 bit !) */	snd_assert((physaddr & 0xff) == 0, return -EINVAL);	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX1, (physaddr >> 8));	err = pcxhr_send_it_dsp(mgr, PCXHR_IT_DOWNLOAD_BOOT, 0);	if (err)		return err;	/* clear hf5 bit */	PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0,		    PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5);

⌨️ 快捷键说明

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