📄 rme32.c
字号:
/* * ALSA driver for RME Digi32, Digi32/8 and Digi32 PRO audio interfaces * * Copyright (c) 2002-2004 Martin Langer <martin-langer@gmx.de>, * Pilo Chambert <pilo.c@wanadoo.fr> * * Thanks to : Anders Torger <torger@ludd.luth.se>, * Henk Hesselink <henk@anda.nl> * for writing the digi96-driver * and RME for all informations. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * * **************************************************************************** * * Note #1 "Sek'd models" ................................... martin 2002-12-07 * * Identical soundcards by Sek'd were labeled: * RME Digi 32 = Sek'd Prodif 32 * RME Digi 32 Pro = Sek'd Prodif 96 * RME Digi 32/8 = Sek'd Prodif Gold * * **************************************************************************** * * Note #2 "full duplex mode" ............................... martin 2002-12-07 * * Full duplex doesn't work. All cards (32, 32/8, 32Pro) are working identical * in this mode. Rec data and play data are using the same buffer therefore. At * first you have got the playing bits in the buffer and then (after playing * them) they were overwitten by the captured sound of the CS8412/14. Both * modes (play/record) are running harmonically hand in hand in the same buffer * and you have only one start bit plus one interrupt bit to control this * paired action. * This is opposite to the latter rme96 where playing and capturing is totally * separated and so their full duplex mode is supported by alsa (using two * start bits and two interrupts for two different buffers). * But due to the wrong sequence of playing and capturing ALSA shows no solved * full duplex support for the rme32 at the moment. That's bad, but I'm not * able to solve it. Are you motivated enough to solve this problem now? Your * patch would be welcome! * * **************************************************************************** * * "The story after the long seeking" -- tiwai * * Ok, the situation regarding the full duplex is now improved a bit. * In the fullduplex mode (given by the module parameter), the hardware buffer * is split to halves for read and write directions at the DMA pointer. * That is, the half above the current DMA pointer is used for write, and * the half below is used for read. To mangle this strange behavior, an * software intermediate buffer is introduced. This is, of course, not good * from the viewpoint of the data transfer efficiency. However, this allows * you to use arbitrary buffer sizes, instead of the fixed I/O buffer size. * * **************************************************************************** */#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/pcm-indirect.h>#include <sound/asoundef.h>#include <sound/initval.h>#include <asm/io.h>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 */static int fullduplex[SNDRV_CARDS]; // = {[0 ... (SNDRV_CARDS - 1)] = 1};module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for RME Digi32 soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for RME Digi32 soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable RME Digi32 soundcard.");module_param_array(fullduplex, bool, NULL, 0444);MODULE_PARM_DESC(fullduplex, "Support full-duplex mode.");MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>, Pilo Chambert <pilo.c@wanadoo.fr>");MODULE_DESCRIPTION("RME Digi32, Digi32/8, Digi32 PRO");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");/* Defines for RME Digi32 series */#define RME32_SPDIF_NCHANNELS 2/* Playback and capture buffer size */#define RME32_BUFFER_SIZE 0x20000/* IO area size */#define RME32_IO_SIZE 0x30000/* IO area offsets */#define RME32_IO_DATA_BUFFER 0x0#define RME32_IO_CONTROL_REGISTER 0x20000#define RME32_IO_GET_POS 0x20000#define RME32_IO_CONFIRM_ACTION_IRQ 0x20004#define RME32_IO_RESET_POS 0x20100/* Write control register bits */#define RME32_WCR_START (1 << 0) /* startbit */#define RME32_WCR_MONO (1 << 1) /* 0=stereo, 1=mono Setting the whole card to mono doesn't seem to be very useful. A software-solution can handle full-duplex with one direction in stereo and the other way in mono. So, the hardware should work all the time in stereo! */#define RME32_WCR_MODE24 (1 << 2) /* 0=16bit, 1=32bit */#define RME32_WCR_SEL (1 << 3) /* 0=input on output, 1=normal playback/capture */#define RME32_WCR_FREQ_0 (1 << 4) /* frequency (play) */#define RME32_WCR_FREQ_1 (1 << 5)#define RME32_WCR_INP_0 (1 << 6) /* input switch */#define RME32_WCR_INP_1 (1 << 7)#define RME32_WCR_RESET (1 << 8) /* Reset address */#define RME32_WCR_MUTE (1 << 9) /* digital mute for output */#define RME32_WCR_PRO (1 << 10) /* 1=professional, 0=consumer */#define RME32_WCR_DS_BM (1 << 11) /* 1=DoubleSpeed (only PRO-Version); 1=BlockMode (only Adat-Version) */#define RME32_WCR_ADAT (1 << 12) /* Adat Mode (only Adat-Version) */#define RME32_WCR_AUTOSYNC (1 << 13) /* AutoSync */#define RME32_WCR_PD (1 << 14) /* DAC Reset (only PRO-Version) */#define RME32_WCR_EMP (1 << 15) /* 1=Emphasis on (only PRO-Version) */#define RME32_WCR_BITPOS_FREQ_0 4#define RME32_WCR_BITPOS_FREQ_1 5#define RME32_WCR_BITPOS_INP_0 6#define RME32_WCR_BITPOS_INP_1 7/* Read control register bits */#define RME32_RCR_AUDIO_ADDR_MASK 0x1ffff#define RME32_RCR_LOCK (1 << 23) /* 1=locked, 0=not locked */#define RME32_RCR_ERF (1 << 26) /* 1=Error, 0=no Error */#define RME32_RCR_FREQ_0 (1 << 27) /* CS841x frequency (record) */#define RME32_RCR_FREQ_1 (1 << 28)#define RME32_RCR_FREQ_2 (1 << 29)#define RME32_RCR_KMODE (1 << 30) /* card mode: 1=PLL, 0=quartz */#define RME32_RCR_IRQ (1 << 31) /* interrupt */#define RME32_RCR_BITPOS_F0 27#define RME32_RCR_BITPOS_F1 28#define RME32_RCR_BITPOS_F2 29/* Input types */#define RME32_INPUT_OPTICAL 0#define RME32_INPUT_COAXIAL 1#define RME32_INPUT_INTERNAL 2#define RME32_INPUT_XLR 3/* Clock modes */#define RME32_CLOCKMODE_SLAVE 0#define RME32_CLOCKMODE_MASTER_32 1#define RME32_CLOCKMODE_MASTER_44 2#define RME32_CLOCKMODE_MASTER_48 3/* Block sizes in bytes */#define RME32_BLOCK_SIZE 8192/* Software intermediate buffer (max) size */#define RME32_MID_BUFFER_SIZE (1024*1024)/* Hardware revisions */#define RME32_32_REVISION 192#define RME32_328_REVISION_OLD 100#define RME32_328_REVISION_NEW 101#define RME32_PRO_REVISION_WITH_8412 192#define RME32_PRO_REVISION_WITH_8414 150struct rme32 { 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 */ 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 */ unsigned int fullduplex_mode; int running; struct snd_pcm_indirect playback_pcm; struct snd_pcm_indirect capture_pcm; 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_rme32_ids[] = { {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, {0,}};MODULE_DEVICE_TABLE(pci, snd_rme32_ids);#define RME32_ISWORKING(rme32) ((rme32)->wcreg & RME32_WCR_START)#define RME32_PRO_WITH_8414(rme32) ((rme32)->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO && (rme32)->rev == RME32_PRO_REVISION_WITH_8414)static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream);static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream);static int snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd);static void snd_rme32_proc_init(struct rme32 * rme32);static int snd_rme32_create_switches(struct snd_card *card, struct rme32 * rme32);static inline unsigned int snd_rme32_pcm_byteptr(struct rme32 * rme32){ return (readl(rme32->iobase + RME32_IO_GET_POS) & RME32_RCR_AUDIO_ADDR_MASK);}/* silence callback for halfduplex mode */static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, snd_pcm_uframes_t count){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->playback_frlog; pos <<= rme32->playback_frlog; memset_io(rme32->iobase + RME32_IO_DATA_BUFFER + pos, 0, count); return 0;}/* copy callback for halfduplex mode */static int snd_rme32_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 rme32 *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->playback_frlog; pos <<= rme32->playback_frlog; if (copy_from_user_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, src, count)) return -EFAULT; return 0;}/* copy callback for halfduplex mode */static int snd_rme32_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 rme32 *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->capture_frlog; pos <<= rme32->capture_frlog; if (copy_to_user_fromio(dst, rme32->iobase + RME32_IO_DATA_BUFFER + pos, count)) return -EFAULT; return 0;}/* * SPDIF I/O capabilities (half-duplex mode) */static struct snd_pcm_hardware snd_rme32_spdif_info = { .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), .rate_min = 32000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = RME32_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0,};/* * ADAT I/O capabilities (half-duplex mode) */static struct snd_pcm_hardware snd_rme32_adat_info ={ .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats= SNDRV_PCM_FMTBIT_S16_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 = RME32_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0,};/* * SPDIF I/O capabilities (full-duplex mode) */static struct snd_pcm_hardware snd_rme32_spdif_fd_info = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), .rate_min = 32000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = RME32_MID_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, .periods_min = 2, .periods_max = RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0,};/* * ADAT I/O capabilities (full-duplex mode) */static struct snd_pcm_hardware snd_rme32_adat_fd_info ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats= SNDRV_PCM_FMTBIT_S16_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 = RME32_MID_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, .periods_min = 2, .periods_max = RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0,};static void snd_rme32_reset_dac(struct rme32 *rme32){ writel(rme32->wcreg | RME32_WCR_PD, rme32->iobase + RME32_IO_CONTROL_REGISTER); writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);}static int snd_rme32_playback_getrate(struct rme32 * rme32){ int rate; rate = ((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_0) & 1) + (((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_1) & 1) << 1); switch (rate) { case 1: rate = 32000; break; case 2: rate = 44100; break; case 3: rate = 48000; break; default: return -1; } return (rme32->wcreg & RME32_WCR_DS_BM) ? rate << 1 : rate;}static int snd_rme32_capture_getrate(struct rme32 * rme32, int *is_adat){ int n; *is_adat = 0; if (rme32->rcreg & RME32_RCR_LOCK) { /* ADAT rate */ *is_adat = 1; } if (rme32->rcreg & RME32_RCR_ERF) { return -1; } /* S/PDIF rate */ n = ((rme32->rcreg >> RME32_RCR_BITPOS_F0) & 1) + (((rme32->rcreg >> RME32_RCR_BITPOS_F1) & 1) << 1) + (((rme32->rcreg >> RME32_RCR_BITPOS_F2) & 1) << 2); if (RME32_PRO_WITH_8414(rme32)) switch (n) { /* supporting the CS8414 */ case 0: case 1: case 2: return -1; case 3: return 96000; case 4: return 88200; case 5: return 48000; case 6: return 44100; case 7: return 32000; default: return -1; break; } else switch (n) { /* supporting the CS8412 */ case 0: return -1; case 1: return 48000; case 2: return 44100; case 3: return 32000; case 4: return 48000; case 5: return 44100; case 6: return 44056; case 7: return 32000; default: break; } return -1;}static int snd_rme32_playback_setrate(struct rme32 * rme32, int rate){ int ds; ds = rme32->wcreg & RME32_WCR_DS_BM; switch (rate) { case 32000: rme32->wcreg &= ~RME32_WCR_DS_BM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -