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

📄 vx_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Driver for Digigram VX soundcards * * Hardware core part * * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> * *   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/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/device.h>#include <linux/firmware.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/asoundef.h>#include <sound/info.h>#include <asm/io.h>#include <sound/vx_core.h>#include "vx_cmd.h"MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");MODULE_DESCRIPTION("Common routines for Digigram VX drivers");MODULE_LICENSE("GPL");/* * snd_vx_delay - delay for the specified time * @xmsec: the time to delay in msec */void snd_vx_delay(vx_core_t *chip, int xmsec){	if (! in_interrupt() && xmsec >= 1000 / HZ)		msleep(xmsec);	else		mdelay(xmsec);}/* * vx_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. */int snd_vx_check_reg_bit(vx_core_t *chip, int reg, int mask, int bit, int time){	unsigned long end_time = jiffies + (time * HZ + 999) / 1000;#ifdef CONFIG_SND_DEBUG	static char *reg_names[VX_REG_MAX] = {		"ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL",		"DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ",		"ACQ", "BIT0", "BIT1", "MIC0", "MIC1", "MIC2",		"MIC3", "INTCSR", "CNTRL", "GPIOC",		"LOFREQ", "HIFREQ", "CSUER", "RUER"	};#endif	do {		if ((snd_vx_inb(chip, reg) & mask) == bit)			return 0;		//snd_vx_delay(chip, 10);	} while (time_after_eq(end_time, jiffies));	snd_printd(KERN_DEBUG "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n", reg_names[reg], mask, snd_vx_inb(chip, reg));	return -EIO;}/* * vx_send_irq_dsp - set command irq bit * @num: the requested IRQ type, IRQ_XXX * * this triggers the specified IRQ request * returns 0 if successful, or a negative error code. *  */static int vx_send_irq_dsp(vx_core_t *chip, int num){	int nirq;	/* wait for Hc = 0 */	if (snd_vx_check_reg_bit(chip, VX_CVR, CVR_HC, 0, 200) < 0)		return -EIO;	nirq = num;	if (vx_has_new_dsp(chip))		nirq += VXP_IRQ_OFFSET;	vx_outb(chip, CVR, (nirq >> 1) | CVR_HC);	return 0;}/* * vx_reset_chk - reset CHK bit on ISR * * returns 0 if successful, or a negative error code. */static int vx_reset_chk(vx_core_t *chip){	/* Reset irq CHK */	if (vx_send_irq_dsp(chip, IRQ_RESET_CHK) < 0)		return -EIO;	/* Wait until CHK = 0 */	if (vx_check_isr(chip, ISR_CHK, 0, 200) < 0)		return -EIO;	return 0;}/* * vx_transfer_end - terminate message transfer * @cmd: IRQ message to send (IRQ_MESS_XXX_END) * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * NB: call with spinlock held! */static int vx_transfer_end(vx_core_t *chip, int cmd){	int err;	if ((err = vx_reset_chk(chip)) < 0)		return err;	/* irq MESS_READ/WRITE_END */	if ((err = vx_send_irq_dsp(chip, cmd)) < 0)		return err;	/* Wait CHK = 1 */	if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)		return err;	/* If error, Read RX */	if ((err = vx_inb(chip, ISR)) & ISR_ERR) {		if ((err = vx_wait_for_rx_full(chip)) < 0) {			snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n");			return err;		}		err = vx_inb(chip, RXH) << 16;		err |= vx_inb(chip, RXM) << 8;		err |= vx_inb(chip, RXL);		snd_printd(KERN_DEBUG "transfer_end: error = 0x%x\n", err);		return -(VX_ERR_MASK | err);	}	return 0;}/* * vx_read_status - return the status rmh * @rmh: rmh record to store the status * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * NB: call with spinlock held! */static int vx_read_status(vx_core_t *chip, struct vx_rmh *rmh){	int i, err, val, size;	/* no read necessary? */	if (rmh->DspStat == RMH_SSIZE_FIXED && rmh->LgStat == 0)		return 0;	/* Wait for RX full (with timeout protection)	 * The first word of status is in RX	 */	err = vx_wait_for_rx_full(chip);	if (err < 0)		return err;	/* Read RX */	val = vx_inb(chip, RXH) << 16;	val |= vx_inb(chip, RXM) << 8;	val |= vx_inb(chip, RXL);	/* If status given by DSP, let's decode its size */	switch (rmh->DspStat) {	case RMH_SSIZE_ARG:		size = val & 0xff;		rmh->Stat[0] = val & 0xffff00;		rmh->LgStat = size + 1;		break;	case RMH_SSIZE_MASK:		/* Let's count the arg numbers from a mask */		rmh->Stat[0] = val;		size = 0;		while (val) {			if (val & 0x01)				size++;			val >>= 1;		}		rmh->LgStat = size + 1;		break;	default:		/* else retrieve the status length given by the driver */		size = rmh->LgStat;		rmh->Stat[0] = val;  /* Val is the status 1st word */		size--;              /* hence adjust remaining length */		break;        }	if (size < 1)		return 0;	snd_assert(size <= SIZE_MAX_STATUS, return -EINVAL);	for (i = 1; i <= size; i++) {		/* trigger an irq MESS_WRITE_NEXT */		err = vx_send_irq_dsp(chip, IRQ_MESS_WRITE_NEXT);		if (err < 0)			return err;		/* Wait for RX full (with timeout protection) */		err = vx_wait_for_rx_full(chip);		if (err < 0)			return err;		rmh->Stat[i] = vx_inb(chip, RXH) << 16;		rmh->Stat[i] |= vx_inb(chip, RXM) <<  8;		rmh->Stat[i] |= vx_inb(chip, RXL);	}	return vx_transfer_end(chip, IRQ_MESS_WRITE_END);}#define MASK_MORE_THAN_1_WORD_COMMAND   0x00008000#define MASK_1_WORD_COMMAND             0x00ff7fff/* * vx_send_msg_nolock - send a DSP message and read back the status * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). *  * this function doesn't call spinlock at all. */int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh){	int i, err;		if (chip->chip_status & VX_STAT_IS_STALE)		return -EBUSY;	if ((err = vx_reset_chk(chip)) < 0) {		snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n");		return err;	}#if 0	printk(KERN_DEBUG "rmh: cmd = 0x%06x, length = %d, stype = %d\n",	       rmh->Cmd[0], rmh->LgCmd, rmh->DspStat);	if (rmh->LgCmd > 1) {		printk(KERN_DEBUG "  ");		for (i = 1; i < rmh->LgCmd; i++)			printk("0x%06x ", rmh->Cmd[i]);		printk("\n");	}#endif	/* Check bit M is set according to length of the command */	if (rmh->LgCmd > 1)		rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND;	else		rmh->Cmd[0] &= MASK_1_WORD_COMMAND;	/* Wait for TX empty */	if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {		snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n");		return err;	}	/* Write Cmd[0] */	vx_outb(chip, TXH, (rmh->Cmd[0] >> 16) & 0xff);	vx_outb(chip, TXM, (rmh->Cmd[0] >> 8) & 0xff);	vx_outb(chip, TXL, rmh->Cmd[0] & 0xff);	/* Trigger irq MESSAGE */	if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) {		snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n");		return err;	}	/* Wait for CHK = 1 */	if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)		return err;	/* If error, get error value from RX */	if (vx_inb(chip, ISR) & ISR_ERR) {		if ((err = vx_wait_for_rx_full(chip)) < 0) {			snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n");			return err;		}		err = vx_inb(chip, RXH) << 16;		err |= vx_inb(chip, RXM) << 8;		err |= vx_inb(chip, RXL);		snd_printd(KERN_DEBUG "msg got error = 0x%x at cmd[0]\n", err);		err = -(VX_ERR_MASK | err);		return err;	}	/* Send the other words */	if (rmh->LgCmd > 1) {		for (i = 1; i < rmh->LgCmd; i++) {			/* Wait for TX ready */			if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {				snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n");				return err;			}			/* Write Cmd[i] */			vx_outb(chip, TXH, (rmh->Cmd[i] >> 16) & 0xff);			vx_outb(chip, TXM, (rmh->Cmd[i] >> 8) & 0xff);			vx_outb(chip, TXL, rmh->Cmd[i] & 0xff);			/* Trigger irq MESS_READ_NEXT */			if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) {				snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n");				return err;			}		}		/* Wait for TX empty */		if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {			snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n");			return err;		}		/* End of transfer */		err = vx_transfer_end(chip, IRQ_MESS_READ_END);		if (err < 0)			return err;	}	return vx_read_status(chip, rmh);}/* * vx_send_msg - send a DSP message with spinlock * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. * see vx_send_msg_nolock(). */int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh){	unsigned long flags;	int err;	spin_lock_irqsave(&chip->lock, flags);	err = vx_send_msg_nolock(chip, rmh);	spin_unlock_irqrestore(&chip->lock, flags);	return err;}/* * vx_send_rih_nolock - send an RIH to xilinx * @cmd: the command to send * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * * this function doesn't call spinlock at all. * * unlike RMH, no command is sent to DSP. */int vx_send_rih_nolock(vx_core_t *chip, int cmd){	int err;	if (chip->chip_status & VX_STAT_IS_STALE)		return -EBUSY;#if 0	printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd);#endif	if ((err = vx_reset_chk(chip)) < 0)		return err;	/* send the IRQ */	if ((err = vx_send_irq_dsp(chip, cmd)) < 0)		return err;	/* Wait CHK = 1 */	if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)		return err;	/* If error, read RX */	if (vx_inb(chip, ISR) & ISR_ERR) {		if ((err = vx_wait_for_rx_full(chip)) < 0)			return err;		err = vx_inb(chip, RXH) << 16;		err |= vx_inb(chip, RXM) << 8;		err |= vx_inb(chip, RXL);		return -(VX_ERR_MASK | err);	}	return 0;}/* * vx_send_rih - send an RIH with spinlock * @cmd: the command to send * * see vx_send_rih_nolock(). */int vx_send_rih(vx_core_t *chip, int cmd){	unsigned long flags;	int err;

⌨️ 快捷键说明

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