aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/rme96.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/rme96.c')
-rw-r--r--sound/pci/rme96.c512
1 files changed, 320 insertions, 192 deletions
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 0e694b011dc..76169929770 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -23,13 +23,12 @@
*
*/
-#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 <linux/module.h>
+#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -55,7 +54,7 @@ MODULE_SUPPORTED_DEVICE("{{RME,Digi96},"
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 bool 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.");
@@ -152,7 +151,7 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
#define RME96_RCR_BITPOS_F1 28
#define RME96_RCR_BITPOS_F2 29
-/* Additonal register bits */
+/* Additional register bits */
#define RME96_AR_WSEL (1 << 0)
#define RME96_AR_ANALOG (1 << 1)
#define RME96_AR_FREQPAD_0 (1 << 2)
@@ -200,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
#define RME96_AD1852_VOL_BITS 14
#define RME96_AD1855_VOL_BITS 10
+/* Defines for snd_rme96_trigger */
+#define RME96_TB_START_PLAYBACK 1
+#define RME96_TB_START_CAPTURE 2
+#define RME96_TB_STOP_PLAYBACK 4
+#define RME96_TB_STOP_CAPTURE 8
+#define RME96_TB_RESET_PLAYPOS 16
+#define RME96_TB_RESET_CAPTUREPOS 32
+#define RME96_TB_CLEAR_PLAYBACK_IRQ 64
+#define RME96_TB_CLEAR_CAPTURE_IRQ 128
+#define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK)
+#define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE)
+#define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \
+ | RME96_RESUME_CAPTURE)
+#define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \
+ | RME96_TB_RESET_PLAYPOS)
+#define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \
+ | RME96_TB_RESET_CAPTUREPOS)
+#define RME96_START_BOTH (RME96_START_PLAYBACK \
+ | RME96_START_CAPTURE)
+#define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \
+ | RME96_TB_CLEAR_PLAYBACK_IRQ)
+#define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \
+ | RME96_TB_CLEAR_CAPTURE_IRQ)
+#define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \
+ | RME96_STOP_CAPTURE)
struct rme96 {
spinlock_t lock;
@@ -216,6 +240,13 @@ struct rme96 {
u8 rev; /* card revision number */
+#ifdef CONFIG_PM_SLEEP
+ u32 playback_pointer;
+ u32 capture_pointer;
+ void *playback_suspend_buffer;
+ void *capture_suspend_buffer;
+#endif
+
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
@@ -232,15 +263,11 @@ struct rme96 {
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, },
+static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = {
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST), 0, },
{ 0, }
};
@@ -276,8 +303,7 @@ snd_rme96_playback_pointer(struct snd_pcm_substream *substream);
static snd_pcm_uframes_t
snd_rme96_capture_pointer(struct snd_pcm_substream *substream);
-static void __devinit
-snd_rme96_proc_init(struct rme96 *rme96);
+static void snd_rme96_proc_init(struct rme96 *rme96);
static int
snd_rme96_create_switches(struct snd_card *card,
@@ -301,20 +327,6 @@ snd_rme96_capture_ptr(struct rme96 *rme96)
}
static int
-snd_rme96_ratecode(int rate)
-{
- switch (rate) {
- case 32000: return SNDRV_PCM_RATE_32000;
- case 44100: return SNDRV_PCM_RATE_44100;
- case 48000: return SNDRV_PCM_RATE_48000;
- case 64000: return SNDRV_PCM_RATE_64000;
- case 88200: return SNDRV_PCM_RATE_88200;
- case 96000: return SNDRV_PCM_RATE_96000;
- }
- return 0;
-}
-
-static int
snd_rme96_playback_silence(struct snd_pcm_substream *substream,
int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos,
@@ -338,9 +350,8 @@ snd_rme96_playback_copy(struct snd_pcm_substream *substream,
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;
+ return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src,
+ count);
}
static int
@@ -353,18 +364,19 @@ snd_rme96_capture_copy(struct snd_pcm_substream *substream,
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;
+ return copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos,
+ count);
}
/*
- * Digital output capabilites (S/PDIF)
+ * 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_SYNC_START |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -388,12 +400,14 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
};
/*
- * Digital input capabilites (S/PDIF)
+ * 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_SYNC_START |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -417,12 +431,14 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
};
/*
- * Digital output capabilites (ADAT)
+ * 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_SYNC_START |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -442,12 +458,14 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info =
};
/*
- * Digital input capabilites (ADAT)
+ * 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_SYNC_START |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -1066,59 +1084,39 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
}
static void
-snd_rme96_playback_start(struct rme96 *rme96,
- int from_pause)
+snd_rme96_trigger(struct rme96 *rme96,
+ int op)
{
- if (!from_pause) {
+ if (op & RME96_TB_RESET_PLAYPOS)
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
- }
-
- rme96->wcreg |= RME96_WCR_START;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
-
-static void
-snd_rme96_capture_start(struct rme96 *rme96,
- int from_pause)
-{
- if (!from_pause) {
+ if (op & RME96_TB_RESET_CAPTUREPOS)
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
- }
-
- rme96->wcreg |= RME96_WCR_START_2;
+ if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) {
+ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if (rme96->rcreg & RME96_RCR_IRQ)
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
+ }
+ if (op & RME96_TB_CLEAR_CAPTURE_IRQ) {
+ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if (rme96->rcreg & RME96_RCR_IRQ_2)
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
+ }
+ if (op & RME96_TB_START_PLAYBACK)
+ rme96->wcreg |= RME96_WCR_START;
+ if (op & RME96_TB_STOP_PLAYBACK)
+ rme96->wcreg &= ~RME96_WCR_START;
+ if (op & RME96_TB_START_CAPTURE)
+ rme96->wcreg |= RME96_WCR_START_2;
+ if (op & RME96_TB_STOP_CAPTURE)
+ rme96->wcreg &= ~RME96_WCR_START_2;
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
-static void
-snd_rme96_playback_stop(struct rme96 *rme96)
-{
- /*
- * Check if there is an unconfirmed IRQ, if so confirm it, or else
- * the hardware will not stop generating interrupts
- */
- rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
- if (rme96->rcreg & RME96_RCR_IRQ) {
- writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
- }
- rme96->wcreg &= ~RME96_WCR_START;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
-static void
-snd_rme96_capture_stop(struct rme96 *rme96)
-{
- rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
- if (rme96->rcreg & RME96_RCR_IRQ_2) {
- writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
- }
- rme96->wcreg &= ~RME96_WCR_START_2;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
static irqreturn_t
snd_rme96_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+ void *dev_id)
{
struct rme96 *rme96 = (struct rme96 *)dev_id;
@@ -1151,6 +1149,25 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = {
.mask = 0
};
+static void
+rme96_set_buffer_size_constraint(struct rme96 *rme96,
+ struct snd_pcm_runtime *runtime)
+{
+ unsigned int size;
+
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
+ if ((size = rme96->playback_periodsize) != 0 ||
+ (size = rme96->capture_periodsize) != 0)
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ size, size);
+ else
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ &hw_constraints_period_bytes);
+}
+
static int
snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
{
@@ -1159,7 +1176,6 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
-
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@@ -1176,12 +1192,11 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
(rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0)
{
/* slave clock */
- runtime->hw.rates = snd_rme96_ratecode(rate);
+ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
rme96->wcreg_spdif_stream = rme96->wcreg_spdif;
rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -1198,7 +1213,6 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
-
runtime->hw = snd_rme96_capture_spdif_info;
if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG &&
(rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0)
@@ -1206,7 +1220,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
if (isadat) {
return -EIO;
}
- runtime->hw.rates = snd_rme96_ratecode(rate);
+ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
@@ -1219,9 +1233,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
rme96->capture_substream = substream;
spin_unlock_irq(&rme96->lock);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
-
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1233,7 +1245,6 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
-
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@@ -1250,12 +1261,11 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
(rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0)
{
/* slave clock */
- runtime->hw.rates = snd_rme96_ratecode(rate);
+ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1267,7 +1277,6 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_set_sync(substream);
-
runtime->hw = snd_rme96_capture_adat_info;
if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
/* makes no sense to use analog input. Note that analog
@@ -1278,7 +1287,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
if (!isadat) {
return -EIO;
}
- runtime->hw.rates = snd_rme96_ratecode(rate);
+ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate);
runtime->hw.rate_min = rate;
runtime->hw.rate_max = rate;
}
@@ -1291,8 +1300,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
rme96->capture_substream = substream;
spin_unlock_irq(&rme96->lock);
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
- snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+ rme96_set_buffer_size_constraint(rme96, runtime);
return 0;
}
@@ -1304,7 +1312,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
}
rme96->playback_substream = NULL;
rme96->playback_periodsize = 0;
@@ -1325,7 +1333,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
rme96->capture_substream = NULL;
rme96->capture_periodsize = 0;
@@ -1340,7 +1348,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
}
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
spin_unlock_irq(&rme96->lock);
@@ -1354,7 +1362,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
}
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
spin_unlock_irq(&rme96->lock);
@@ -1366,41 +1374,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ bool sync;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96)
+ snd_pcm_trigger_done(s, substream);
+ }
+
+ sync = (rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group ==
+ rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (!RME96_ISPLAYING(rme96)) {
- if (substream != rme96->playback_substream) {
+ if (substream != rme96->playback_substream)
return -EBUSY;
- }
- snd_rme96_playback_start(rme96, 0);
+ snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
+ : RME96_START_PLAYBACK);
}
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
if (RME96_ISPLAYING(rme96)) {
- if (substream != rme96->playback_substream) {
+ if (substream != rme96->playback_substream)
return -EBUSY;
- }
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+ : RME96_STOP_PLAYBACK);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
- }
+ if (RME96_ISPLAYING(rme96))
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+ : RME96_STOP_PLAYBACK);
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_start(rme96, 1);
- }
+ if (!RME96_ISPLAYING(rme96))
+ snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
+ : RME96_RESUME_PLAYBACK);
break;
-
+
default:
return -EINVAL;
}
+
return 0;
}
@@ -1409,38 +1431,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ bool sync;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96)
+ snd_pcm_trigger_done(s, substream);
+ }
+
+ sync = (rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group ==
+ rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (!RME96_ISRECORDING(rme96)) {
- if (substream != rme96->capture_substream) {
+ if (substream != rme96->capture_substream)
return -EBUSY;
- }
- snd_rme96_capture_start(rme96, 0);
+ snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
+ : RME96_START_CAPTURE);
}
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
if (RME96_ISRECORDING(rme96)) {
- if (substream != rme96->capture_substream) {
+ if (substream != rme96->capture_substream)
return -EBUSY;
- }
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+ : RME96_STOP_CAPTURE);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
- }
+ if (RME96_ISRECORDING(rme96))
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+ : RME96_STOP_CAPTURE);
break;
+ case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_start(rme96, 1);
- }
+ if (!RME96_ISRECORDING(rme96))
+ snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
+ : RME96_RESUME_CAPTURE);
break;
-
+
default:
return -EINVAL;
}
@@ -1521,8 +1556,7 @@ snd_rme96_free(void *private_data)
return;
}
if (rme96->irq >= 0) {
- snd_rme96_playback_stop(rme96);
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_BOTH);
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
free_irq(rme96->irq, (void *)rme96);
@@ -1536,24 +1570,28 @@ snd_rme96_free(void *private_data)
pci_release_regions(rme96->pci);
rme96->port = 0;
}
+#ifdef CONFIG_PM_SLEEP
+ vfree(rme96->playback_suspend_buffer);
+ vfree(rme96->capture_suspend_buffer);
+#endif
pci_disable_device(rme96->pci);
}
static void
snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->spdif_pcm = NULL;
}
static void
snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
{
- struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+ struct rme96 *rme96 = pcm->private_data;
rme96->adat_pcm = NULL;
}
-static int __devinit
+static int
snd_rme96_create(struct rme96 *rme96)
{
struct pci_dev *pci = rme96->pci;
@@ -1569,16 +1607,20 @@ snd_rme96_create(struct rme96 *rme96)
return err;
rme96->port = pci_resource_start(rme96->pci, 0);
- if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) {
- snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
- return -EBUSY;
+ rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE);
+ if (!rme96->iobase) {
+ dev_err(rme96->card->dev,
+ "unable to remap memory region 0x%lx-0x%lx\n",
+ rme96->port, rme96->port + RME96_IO_SIZE - 1);
+ return -ENOMEM;
}
- rme96->irq = pci->irq;
- if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
- snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
- return -ENOMEM;
+ if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, rme96)) {
+ dev_err(rme96->card->dev, "unable to grab IRQ %d\n", pci->irq);
+ return -EBUSY;
}
+ rme96->irq = pci->irq;
/* read the card's revision number */
pci_read_config_byte(pci, 8, &rme96->rev);
@@ -1620,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96)
rme96->capture_periodsize = 0;
/* make sure playback/capture is stopped, if by some reason active */
- snd_rme96_playback_stop(rme96);
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, RME96_STOP_BOTH);
/* set default values in registers */
rme96->wcreg =
@@ -1674,7 +1715,7 @@ static void
snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
int n;
- struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+ struct rme96 *rme96 = entry->private_data;
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
@@ -1799,28 +1840,20 @@ snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer
}
}
-static void __devinit
-snd_rme96_proc_init(struct rme96 *rme96)
+static void snd_rme96_proc_init(struct rme96 *rme96)
{
struct snd_info_entry *entry;
if (! snd_card_proc_new(rme96->card, "rme96", &entry))
- snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read);
+ snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read);
}
/*
* control interface
*/
-static int
-snd_rme96_info_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_rme96_info_loopback_control snd_ctl_boolean_mono_info
+
static int
snd_rme96_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
@@ -2210,22 +2243,25 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
{
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
int change = 0;
+ unsigned int vol, maxvol;
- if (!RME96_HAS_ANALOG_OUT(rme96)) {
+
+ if (!RME96_HAS_ANALOG_OUT(rme96))
return -EINVAL;
- }
+ maxvol = RME96_185X_MAX_OUT(rme96);
spin_lock_irq(&rme96->lock);
- if (u->value.integer.value[0] != rme96->vol[0]) {
- rme96->vol[0] = u->value.integer.value[0];
- change = 1;
- }
- if (u->value.integer.value[1] != rme96->vol[1]) {
- rme96->vol[1] = u->value.integer.value[1];
- change = 1;
- }
- if (change) {
- snd_rme96_apply_dac_volume(rme96);
+ vol = u->value.integer.value[0];
+ if (vol != rme96->vol[0] && vol <= maxvol) {
+ rme96->vol[0] = vol;
+ change = 1;
+ }
+ vol = u->value.integer.value[1];
+ if (vol != rme96->vol[1] && vol <= maxvol) {
+ rme96->vol[1] = vol;
+ change = 1;
}
+ if (change)
+ snd_rme96_apply_dac_volume(rme96);
spin_unlock_irq(&rme96->lock);
return change;
@@ -2338,12 +2374,96 @@ snd_rme96_create_switches(struct snd_card *card,
* Card initialisation
*/
+#ifdef CONFIG_PM_SLEEP
+
+static int rme96_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct rme96 *rme96 = card->private_data;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ snd_pcm_suspend(rme96->playback_substream);
+ snd_pcm_suspend(rme96->capture_substream);
+
+ /* save capture & playback pointers */
+ rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS)
+ & RME96_RCR_AUDIO_ADDR_MASK;
+ rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS)
+ & RME96_RCR_AUDIO_ADDR_MASK;
+
+ /* save playback and capture buffers */
+ memcpy_fromio(rme96->playback_suspend_buffer,
+ rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE);
+ memcpy_fromio(rme96->capture_suspend_buffer,
+ rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE);
+
+ /* disable the DAC */
+ rme96->areg &= ~RME96_AR_DAC_EN;
+ writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+
+ pci_disable_device(pci);
+ pci_save_state(pci);
+
+ return 0;
+}
+
+static int rme96_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct rme96 *rme96 = card->private_data;
+
+ pci_restore_state(pci);
+ if (pci_enable_device(pci) < 0) {
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ /* reset playback and record buffer pointers */
+ writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
+ + rme96->playback_pointer);
+ writel(0, rme96->iobase + RME96_IO_SET_REC_POS
+ + rme96->capture_pointer);
+
+ /* restore playback and capture buffers */
+ memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER,
+ rme96->playback_suspend_buffer, RME96_BUFFER_SIZE);
+ memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER,
+ rme96->capture_suspend_buffer, RME96_BUFFER_SIZE);
+
+ /* reset the ADC */
+ writel(rme96->areg | RME96_AR_PD2,
+ rme96->iobase + RME96_IO_ADDITIONAL_REG);
+ writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+
+ /* reset and enable DAC, restore analog volume */
+ snd_rme96_reset_dac(rme96);
+ rme96->areg |= RME96_AR_DAC_EN;
+ writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+ if (RME96_HAS_ANALOG_OUT(rme96)) {
+ usleep_range(3000, 10000);
+ snd_rme96_apply_dac_volume(rme96);
+ }
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume);
+#define RME96_PM_OPS &rme96_pm
+#else
+#define RME96_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static void snd_rme96_card_free(struct snd_card *card)
{
snd_rme96_free(card->private_data);
}
-static int __devinit
+static int
snd_rme96_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -2360,19 +2480,36 @@ snd_rme96_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct rme96))) == NULL)
- return -ENOMEM;
+ err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(struct rme96), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_rme96_card_free;
- rme96 = (struct rme96 *)card->private_data;
+ rme96 = card->private_data;
rme96->card = card;
rme96->pci = pci;
- snd_card_set_dev(card, &pci->dev);
if ((err = snd_rme96_create(rme96)) < 0) {
snd_card_free(card);
return err;
}
+#ifdef CONFIG_PM_SLEEP
+ rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+ if (!rme96->playback_suspend_buffer) {
+ dev_err(card->dev,
+ "Failed to allocate playback suspend buffer!\n");
+ snd_card_free(card);
+ return -ENOMEM;
+ }
+ rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+ if (!rme96->capture_suspend_buffer) {
+ dev_err(card->dev,
+ "Failed to allocate capture suspend buffer!\n");
+ snd_card_free(card);
+ return -ENOMEM;
+ }
+#endif
+
strcpy(card->driver, "Digi96");
switch (rme96->pci->device) {
case PCI_DEVICE_ID_RME_DIGI96:
@@ -2405,28 +2542,19 @@ snd_rme96_probe(struct pci_dev *pci,
return 0;
}
-static void __devexit snd_rme96_remove(struct pci_dev *pci)
+static void snd_rme96_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
- .name = "RME Digi96",
+static struct pci_driver rme96_driver = {
+ .name = KBUILD_MODNAME,
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
- .remove = __devexit_p(snd_rme96_remove),
+ .remove = snd_rme96_remove,
+ .driver = {
+ .pm = RME96_PM_OPS,
+ },
};
-static int __init alsa_card_rme96_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme96_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme96_init)
-module_exit(alsa_card_rme96_exit)
+module_pci_driver(rme96_driver);