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

📄 rme96.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   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 + -