📄 rme96.c
字号:
/* * ALSA driver for RME Digi96, Digi96/8 and Digi96/8 PRO/PAD/PST audio * interfaces * * Copyright (c) 2000, 2001 Anders Torger <torger@ludd.luth.se> * * Thanks to Henk Hesselink <henk@anda.nl> for the analog volume control * code. * * 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/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/info.h>#include <sound/control.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/asoundef.h>#include <sound/initval.h>#include <asm/io.h>/* note, two last pcis should be equal, it is not a bug */MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");MODULE_DESCRIPTION("RME Digi96, Digi96/8, Digi96/8 PRO, Digi96/8 PST, " "Digi96/8 PAD");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{RME,Digi96}," "{RME,Digi96/8}," "{RME,Digi96/8 PRO}," "{RME,Digi96/8 PST}," "{RME,Digi96/8 PAD}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for RME Digi96 soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for RME Digi96 soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");/* * Defines for RME Digi96 series, from internal RME reference documents * dated 12.01.00 */#define RME96_SPDIF_NCHANNELS 2/* Playback and capture buffer size */#define RME96_BUFFER_SIZE 0x10000/* IO area size */#define RME96_IO_SIZE 0x60000/* IO area offsets */#define RME96_IO_PLAY_BUFFER 0x0#define RME96_IO_REC_BUFFER 0x10000#define RME96_IO_CONTROL_REGISTER 0x20000#define RME96_IO_ADDITIONAL_REG 0x20004#define RME96_IO_CONFIRM_PLAY_IRQ 0x20008#define RME96_IO_CONFIRM_REC_IRQ 0x2000C#define RME96_IO_SET_PLAY_POS 0x40000#define RME96_IO_RESET_PLAY_POS 0x4FFFC#define RME96_IO_SET_REC_POS 0x50000#define RME96_IO_RESET_REC_POS 0x5FFFC#define RME96_IO_GET_PLAY_POS 0x20000#define RME96_IO_GET_REC_POS 0x30000/* Write control register bits */#define RME96_WCR_START (1 << 0)#define RME96_WCR_START_2 (1 << 1)#define RME96_WCR_GAIN_0 (1 << 2)#define RME96_WCR_GAIN_1 (1 << 3)#define RME96_WCR_MODE24 (1 << 4)#define RME96_WCR_MODE24_2 (1 << 5)#define RME96_WCR_BM (1 << 6)#define RME96_WCR_BM_2 (1 << 7)#define RME96_WCR_ADAT (1 << 8)#define RME96_WCR_FREQ_0 (1 << 9)#define RME96_WCR_FREQ_1 (1 << 10)#define RME96_WCR_DS (1 << 11)#define RME96_WCR_PRO (1 << 12)#define RME96_WCR_EMP (1 << 13)#define RME96_WCR_SEL (1 << 14)#define RME96_WCR_MASTER (1 << 15)#define RME96_WCR_PD (1 << 16)#define RME96_WCR_INP_0 (1 << 17)#define RME96_WCR_INP_1 (1 << 18)#define RME96_WCR_THRU_0 (1 << 19)#define RME96_WCR_THRU_1 (1 << 20)#define RME96_WCR_THRU_2 (1 << 21)#define RME96_WCR_THRU_3 (1 << 22)#define RME96_WCR_THRU_4 (1 << 23)#define RME96_WCR_THRU_5 (1 << 24)#define RME96_WCR_THRU_6 (1 << 25)#define RME96_WCR_THRU_7 (1 << 26)#define RME96_WCR_DOLBY (1 << 27)#define RME96_WCR_MONITOR_0 (1 << 28)#define RME96_WCR_MONITOR_1 (1 << 29)#define RME96_WCR_ISEL (1 << 30)#define RME96_WCR_IDIS (1 << 31)#define RME96_WCR_BITPOS_GAIN_0 2#define RME96_WCR_BITPOS_GAIN_1 3#define RME96_WCR_BITPOS_FREQ_0 9#define RME96_WCR_BITPOS_FREQ_1 10#define RME96_WCR_BITPOS_INP_0 17#define RME96_WCR_BITPOS_INP_1 18#define RME96_WCR_BITPOS_MONITOR_0 28#define RME96_WCR_BITPOS_MONITOR_1 29/* Read control register bits */#define RME96_RCR_AUDIO_ADDR_MASK 0xFFFF#define RME96_RCR_IRQ_2 (1 << 16)#define RME96_RCR_T_OUT (1 << 17)#define RME96_RCR_DEV_ID_0 (1 << 21)#define RME96_RCR_DEV_ID_1 (1 << 22)#define RME96_RCR_LOCK (1 << 23)#define RME96_RCR_VERF (1 << 26)#define RME96_RCR_F0 (1 << 27)#define RME96_RCR_F1 (1 << 28)#define RME96_RCR_F2 (1 << 29)#define RME96_RCR_AUTOSYNC (1 << 30)#define RME96_RCR_IRQ (1 << 31)#define RME96_RCR_BITPOS_F0 27#define RME96_RCR_BITPOS_F1 28#define RME96_RCR_BITPOS_F2 29/* Additonal register bits */#define RME96_AR_WSEL (1 << 0)#define RME96_AR_ANALOG (1 << 1)#define RME96_AR_FREQPAD_0 (1 << 2)#define RME96_AR_FREQPAD_1 (1 << 3)#define RME96_AR_FREQPAD_2 (1 << 4)#define RME96_AR_PD2 (1 << 5)#define RME96_AR_DAC_EN (1 << 6)#define RME96_AR_CLATCH (1 << 7)#define RME96_AR_CCLK (1 << 8)#define RME96_AR_CDATA (1 << 9)#define RME96_AR_BITPOS_F0 2#define RME96_AR_BITPOS_F1 3#define RME96_AR_BITPOS_F2 4/* Monitor tracks */#define RME96_MONITOR_TRACKS_1_2 0#define RME96_MONITOR_TRACKS_3_4 1#define RME96_MONITOR_TRACKS_5_6 2#define RME96_MONITOR_TRACKS_7_8 3/* Attenuation */#define RME96_ATTENUATION_0 0#define RME96_ATTENUATION_6 1#define RME96_ATTENUATION_12 2#define RME96_ATTENUATION_18 3/* Input types */#define RME96_INPUT_OPTICAL 0#define RME96_INPUT_COAXIAL 1#define RME96_INPUT_INTERNAL 2#define RME96_INPUT_XLR 3#define RME96_INPUT_ANALOG 4/* Clock modes */#define RME96_CLOCKMODE_SLAVE 0#define RME96_CLOCKMODE_MASTER 1#define RME96_CLOCKMODE_WORDCLOCK 2/* Block sizes in bytes */#define RME96_SMALL_BLOCK_SIZE 2048#define RME96_LARGE_BLOCK_SIZE 8192/* Volume control */#define RME96_AD1852_VOL_BITS 14#define RME96_AD1855_VOL_BITS 10struct rme96 { spinlock_t lock; int irq; unsigned long port; void __iomem *iobase; u32 wcreg; /* cached write control register value */ u32 wcreg_spdif; /* S/PDIF setup */ u32 wcreg_spdif_stream; /* S/PDIF setup (temporary) */ u32 rcreg; /* cached read control register value */ u32 areg; /* cached additional register value */ u16 vol[2]; /* cached volume of analog output */ u8 rev; /* card revision number */ struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; int playback_frlog; /* log2 of framesize */ int capture_frlog; size_t playback_periodsize; /* in bytes, zero if not used */ size_t capture_periodsize; /* in bytes, zero if not used */ struct snd_card *card; struct snd_pcm *spdif_pcm; struct snd_pcm *adat_pcm; struct pci_dev *pci; struct snd_kcontrol *spdif_ctl;};static struct pci_device_id snd_rme96_ids[] = { { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { 0, }};MODULE_DEVICE_TABLE(pci, snd_rme96_ids);#define RME96_ISPLAYING(rme96) ((rme96)->wcreg & RME96_WCR_START)#define RME96_ISRECORDING(rme96) ((rme96)->wcreg & RME96_WCR_START_2)#define RME96_HAS_ANALOG_IN(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST)#define RME96_HAS_ANALOG_OUT(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PRO || \ (rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST)#define RME96_DAC_IS_1852(rme96) (RME96_HAS_ANALOG_OUT(rme96) && (rme96)->rev >= 4)#define RME96_DAC_IS_1855(rme96) (((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST && (rme96)->rev < 4) || \ ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PRO && (rme96)->rev == 2))#define RME96_185X_MAX_OUT(rme96) ((1 << (RME96_DAC_IS_1852(rme96) ? RME96_AD1852_VOL_BITS : RME96_AD1855_VOL_BITS)) - 1)static intsnd_rme96_playback_prepare(struct snd_pcm_substream *substream);static intsnd_rme96_capture_prepare(struct snd_pcm_substream *substream);static intsnd_rme96_playback_trigger(struct snd_pcm_substream *substream, int cmd);static intsnd_rme96_capture_trigger(struct snd_pcm_substream *substream, int cmd);static snd_pcm_uframes_tsnd_rme96_playback_pointer(struct snd_pcm_substream *substream);static snd_pcm_uframes_tsnd_rme96_capture_pointer(struct snd_pcm_substream *substream);static void __devinit snd_rme96_proc_init(struct rme96 *rme96);static intsnd_rme96_create_switches(struct snd_card *card, struct rme96 *rme96);static intsnd_rme96_getinputtype(struct rme96 *rme96);static inline unsigned intsnd_rme96_playback_ptr(struct rme96 *rme96){ return (readl(rme96->iobase + RME96_IO_GET_PLAY_POS) & RME96_RCR_AUDIO_ADDR_MASK) >> rme96->playback_frlog;}static inline unsigned intsnd_rme96_capture_ptr(struct rme96 *rme96){ return (readl(rme96->iobase + RME96_IO_GET_REC_POS) & RME96_RCR_AUDIO_ADDR_MASK) >> rme96->capture_frlog;}static intsnd_rme96_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, snd_pcm_uframes_t count){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->playback_frlog; pos <<= rme96->playback_frlog; memset_io(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, 0, count); return 0;}static intsnd_rme96_playback_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->playback_frlog; pos <<= rme96->playback_frlog; copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, count); return 0;}static intsnd_rme96_capture_copy(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->capture_frlog; pos <<= rme96->capture_frlog; copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, count); return 0;}/* * Digital output capabilities (S/PDIF) */static struct snd_pcm_hardware snd_rme96_playback_spdif_info ={ .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), .rate_min = 32000, .rate_max = 96000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = RME96_BUFFER_SIZE, .period_bytes_min = RME96_SMALL_BLOCK_SIZE, .period_bytes_max = RME96_LARGE_BLOCK_SIZE, .periods_min = RME96_BUFFER_SIZE / RME96_LARGE_BLOCK_SIZE, .periods_max = RME96_BUFFER_SIZE / RME96_SMALL_BLOCK_SIZE, .fifo_size = 0,};/* * Digital input capabilities (S/PDIF) */static struct snd_pcm_hardware snd_rme96_capture_spdif_info ={ .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), .rate_min = 32000, .rate_max = 96000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = RME96_BUFFER_SIZE, .period_bytes_min = RME96_SMALL_BLOCK_SIZE, .period_bytes_max = RME96_LARGE_BLOCK_SIZE, .periods_min = RME96_BUFFER_SIZE / RME96_LARGE_BLOCK_SIZE, .periods_max = RME96_BUFFER_SIZE / RME96_SMALL_BLOCK_SIZE, .fifo_size = 0,};/* * Digital output capabilities (ADAT) */static struct snd_pcm_hardware snd_rme96_playback_adat_info ={ .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), .rate_min = 44100, .rate_max = 48000, .channels_min = 8, .channels_max = 8, .buffer_bytes_max = RME96_BUFFER_SIZE, .period_bytes_min = RME96_SMALL_BLOCK_SIZE, .period_bytes_max = RME96_LARGE_BLOCK_SIZE, .periods_min = RME96_BUFFER_SIZE / RME96_LARGE_BLOCK_SIZE, .periods_max = RME96_BUFFER_SIZE / RME96_SMALL_BLOCK_SIZE, .fifo_size = 0,};/* * Digital input capabilities (ADAT) */static struct snd_pcm_hardware snd_rme96_capture_adat_info ={ .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), .rate_min = 44100, .rate_max = 48000, .channels_min = 8, .channels_max = 8, .buffer_bytes_max = RME96_BUFFER_SIZE, .period_bytes_min = RME96_SMALL_BLOCK_SIZE, .period_bytes_max = RME96_LARGE_BLOCK_SIZE, .periods_min = RME96_BUFFER_SIZE / RME96_LARGE_BLOCK_SIZE, .periods_max = RME96_BUFFER_SIZE / RME96_SMALL_BLOCK_SIZE, .fifo_size = 0,};/* * The CDATA, CCLK and CLATCH bits can be used to write to the SPI interface * of the AD1852 or AD1852 D/A converter on the board. CDATA must be set up * on the falling edge of CCLK and be stable on the rising edge. The rising
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -