📄 vx222_ops.c
字号:
/* * Driver for Digigram VX222 V2/Mic soundcards * * VX222-specific low-level routines * * 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/device.h>#include <linux/firmware.h>#include <sound/core.h>#include <sound/control.h>#include <asm/io.h>#include "vx222.h"static int vx2_reg_offset[VX_REG_MAX] = { [VX_ICR] = 0x00, [VX_CVR] = 0x04, [VX_ISR] = 0x08, [VX_IVR] = 0x0c, [VX_RXH] = 0x14, [VX_RXM] = 0x18, [VX_RXL] = 0x1c, [VX_DMA] = 0x10, [VX_CDSP] = 0x20, [VX_CFG] = 0x24, [VX_RUER] = 0x28, [VX_DATA] = 0x2c, [VX_STATUS] = 0x30, [VX_LOFREQ] = 0x34, [VX_HIFREQ] = 0x38, [VX_CSUER] = 0x3c, [VX_SELMIC] = 0x40, [VX_COMPOT] = 0x44, // Write: POTENTIOMETER ; Read: COMPRESSION LEVEL activate [VX_SCOMPR] = 0x48, // Read: COMPRESSION THRESHOLD activate [VX_GLIMIT] = 0x4c, // Read: LEVEL LIMITATION activate [VX_INTCSR] = 0x4c, // VX_INTCSR_REGISTER_OFFSET [VX_CNTRL] = 0x50, // VX_CNTRL_REGISTER_OFFSET [VX_GPIOC] = 0x54, // VX_GPIOC (new with PLX9030)};static int vx2_reg_index[VX_REG_MAX] = { [VX_ICR] = 1, [VX_CVR] = 1, [VX_ISR] = 1, [VX_IVR] = 1, [VX_RXH] = 1, [VX_RXM] = 1, [VX_RXL] = 1, [VX_DMA] = 1, [VX_CDSP] = 1, [VX_CFG] = 1, [VX_RUER] = 1, [VX_DATA] = 1, [VX_STATUS] = 1, [VX_LOFREQ] = 1, [VX_HIFREQ] = 1, [VX_CSUER] = 1, [VX_SELMIC] = 1, [VX_COMPOT] = 1, [VX_SCOMPR] = 1, [VX_GLIMIT] = 1, [VX_INTCSR] = 0, /* on the PLX */ [VX_CNTRL] = 0, /* on the PLX */ [VX_GPIOC] = 0, /* on the PLX */};static inline unsigned long vx2_reg_addr(vx_core_t *_chip, int reg){ struct snd_vx222 *chip = (struct snd_vx222 *)_chip; return chip->port[vx2_reg_index[reg]] + vx2_reg_offset[reg];}/** * snd_vx_inb - read a byte from the register * @offset: register enum */static unsigned char vx2_inb(vx_core_t *chip, int offset){ return inb(vx2_reg_addr(chip, offset));}/** * snd_vx_outb - write a byte on the register * @offset: the register offset * @val: the value to write */static void vx2_outb(vx_core_t *chip, int offset, unsigned char val){ outb(val, vx2_reg_addr(chip, offset)); //printk("outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));}/** * snd_vx_inl - read a 32bit word from the register * @offset: register enum */static unsigned int vx2_inl(vx_core_t *chip, int offset){ return inl(vx2_reg_addr(chip, offset));}/** * snd_vx_outl - write a 32bit word on the register * @offset: the register enum * @val: the value to write */static void vx2_outl(vx_core_t *chip, int offset, unsigned int val){ // printk("outl: %x -> %x\n", val, vx2_reg_addr(chip, offset)); outl(val, vx2_reg_addr(chip, offset));}/* * redefine macros to call directly */#undef vx_inb#define vx_inb(chip,reg) vx2_inb((vx_core_t*)(chip), VX_##reg)#undef vx_outb#define vx_outb(chip,reg,val) vx2_outb((vx_core_t*)(chip), VX_##reg, val)#undef vx_inl#define vx_inl(chip,reg) vx2_inl((vx_core_t*)(chip), VX_##reg)#undef vx_outl#define vx_outl(chip,reg,val) vx2_outl((vx_core_t*)(chip), VX_##reg, val)/* * vx_reset_dsp - reset the DSP */#define XX_DSP_RESET_WAIT_TIME 2 /* ms */static void vx2_reset_dsp(vx_core_t *_chip){ struct snd_vx222 *chip = (struct snd_vx222 *)_chip; /* set the reset dsp bit to 0 */ vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_DSP_RESET_MASK); snd_vx_delay(_chip, XX_DSP_RESET_WAIT_TIME); chip->regCDSP |= VX_CDSP_DSP_RESET_MASK; /* set the reset dsp bit to 1 */ vx_outl(chip, CDSP, chip->regCDSP);}static int vx2_test_xilinx(vx_core_t *_chip){ struct snd_vx222 *chip = (struct snd_vx222 *)_chip; unsigned int data; snd_printdd("testing xilinx...\n"); /* This test uses several write/read sequences on TEST0 and TEST1 bits * to figure out whever or not the xilinx was correctly loaded */ /* We write 1 on CDSP.TEST0. We should get 0 on STATUS.TEST0. */ vx_outl(chip, CDSP, chip->regCDSP | VX_CDSP_TEST0_MASK); vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if ((data & VX_STATUS_VAL_TEST0_MASK) == VX_STATUS_VAL_TEST0_MASK) { snd_printdd("bad!\n"); return -ENODEV; } /* We write 0 on CDSP.TEST0. We should get 1 on STATUS.TEST0. */ vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_TEST0_MASK); vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if (! (data & VX_STATUS_VAL_TEST0_MASK)) { snd_printdd("bad! #2\n"); return -ENODEV; } if (_chip->type == VX_TYPE_BOARD) { /* not implemented on VX_2_BOARDS */ /* We write 1 on CDSP.TEST1. We should get 0 on STATUS.TEST1. */ vx_outl(chip, CDSP, chip->regCDSP | VX_CDSP_TEST1_MASK); vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if ((data & VX_STATUS_VAL_TEST1_MASK) == VX_STATUS_VAL_TEST1_MASK) { snd_printdd("bad! #3\n"); return -ENODEV; } /* We write 0 on CDSP.TEST1. We should get 1 on STATUS.TEST1. */ vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_TEST1_MASK); vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if (! (data & VX_STATUS_VAL_TEST1_MASK)) { snd_printdd("bad! #4\n"); return -ENODEV; } } snd_printdd("ok, xilinx fine.\n"); return 0;}/** * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. * @do_write: 0 = read, 1 = set up for DMA write */static void vx2_setup_pseudo_dma(vx_core_t *chip, int do_write){ /* Interrupt mode and HREQ pin enabled for host transmit data transfers * (in case of the use of the pseudo-dma facility). */ vx_outl(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); /* Reset the pseudo-dma register (in case of the use of the * pseudo-dma facility). */ vx_outl(chip, RESET_DMA, 0);}/* * vx_release_pseudo_dma - disable the pseudo-DMA mode */static inline void vx2_release_pseudo_dma(vx_core_t *chip){ /* HREQ pin disabled. */ vx_outl(chip, ICR, 0);}/* pseudo-dma write */static void vx2_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count){ unsigned long port = vx2_reg_addr(chip, VX_DMA); int offset = pipe->hw_ptr; u32 *addr = (u32 *)(runtime->dma_area + offset); snd_assert(count % 4 == 0, return); vx2_setup_pseudo_dma(chip, 1); /* Transfer using pseudo-dma. */ if (offset + count > pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ while (length-- > 0) { outl(cpu_to_le32(*addr), port); addr++; } addr = (u32 *)runtime->dma_area; pipe->hw_ptr = 0; } pipe->hw_ptr += count; count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ while (count-- > 0) { outl(cpu_to_le32(*addr), port); addr++; } vx2_release_pseudo_dma(chip);}/* pseudo dma read */static void vx2_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count){ int offset = pipe->hw_ptr; u32 *addr = (u32 *)(runtime->dma_area + offset); unsigned long port = vx2_reg_addr(chip, VX_DMA); snd_assert(count % 4 == 0, return); vx2_setup_pseudo_dma(chip, 0); /* Transfer using pseudo-dma. */ if (offset + count > pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ while (length-- > 0) *addr++ = le32_to_cpu(inl(port)); addr = (u32 *)runtime->dma_area; pipe->hw_ptr = 0; } pipe->hw_ptr += count; count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ while (count-- > 0) *addr++ = le32_to_cpu(inl(port)); vx2_release_pseudo_dma(chip);}#define VX_XILINX_RESET_MASK 0x40000000#define VX_USERBIT0_MASK 0x00000004#define VX_USERBIT1_MASK 0x00000020#define VX_CNTRL_REGISTER_VALUE 0x00172012/* * transfer counts bits to PLX */static int put_xilinx_data(vx_core_t *chip, unsigned int port, unsigned int counts, unsigned char data){ unsigned int i; for (i = 0; i < counts; i++) { unsigned int val; /* set the clock bit to 0. */ val = VX_CNTRL_REGISTER_VALUE & ~VX_USERBIT0_MASK; vx2_outl(chip, port, val); vx2_inl(chip, port); udelay(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -